4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
13 ** This is a utility program designed to aid running regressions tests on
14 ** the SQLite library using data from an external fuzzer, such as American
15 ** Fuzzy Lop (AFL) (http://lcamtuf.coredump.cx/afl/).
17 ** This program reads content from an SQLite database file with the following
21 ** dbid INTEGER PRIMARY KEY, -- database id
22 ** dbcontent BLOB -- database disk file image
25 ** sqlid INTEGER PRIMARY KEY, -- SQL script id
26 ** sqltext TEXT -- Text of SQL statements to run
28 ** CREATE TABLE IF NOT EXISTS readme(
29 ** msg TEXT -- Human-readable description of this test collection
32 ** For each database file in the DB table, the SQL text in the XSQL table
33 ** is run against that database. All README.MSG values are printed prior
34 ** to the start of the test (unless the --quiet option is used). If the
35 ** DB table is empty, then all entries in XSQL are run against an empty
36 ** in-memory database.
38 ** This program is looking for crashes, assertion faults, and/or memory leaks.
39 ** No attempt is made to verify the output. The assumption is that either all
40 ** of the database files or all of the SQL statements are malformed inputs,
41 ** generated by a fuzzer, that need to be checked to make sure they do not
42 ** present a security risk.
44 ** This program also includes some command-line options to help with
45 ** creation and maintenance of the source content database. The command
47 ** ./fuzzcheck database.db --load-sql FILE...
49 ** Loads all FILE... arguments into the XSQL table. The --load-db option
50 ** works the same but loads the files into the DB table. The -m option can
51 ** be used to initialize the README table. The "database.db" file is created
52 ** if it does not previously exist. Example:
54 ** ./fuzzcheck new.db --load-sql *.sql
55 ** ./fuzzcheck new.db --load-db *.db
56 ** ./fuzzcheck new.db -m 'New test cases'
58 ** The three commands above will create the "new.db" file and initialize all
59 ** tables. Then do "./fuzzcheck new.db" to run the tests.
63 ** If fuzzcheck does crash, it can be run in the debugger and the content
64 ** of the global variable g.zTextName[] will identify the specific XSQL and
65 ** DB values that were running when the crash occurred.
74 #define ISSPACE(X) isspace((unsigned char)(X))
75 #define ISDIGIT(X) isdigit((unsigned char)(X))
84 ** Files in the virtual file system.
86 typedef struct VFile VFile
;
88 char *zFilename
; /* Filename. NULL for delete-on-close. From malloc() */
89 int sz
; /* Size of the file in bytes */
90 int nRef
; /* Number of references to this file */
91 unsigned char *a
; /* Content of the file. From malloc() */
93 typedef struct VHandle VHandle
;
95 sqlite3_file base
; /* Base class. Must be first */
96 VFile
*pVFile
; /* The underlying file */
100 ** The value of a database file template, or of an SQL script
102 typedef struct Blob Blob
;
104 Blob
*pNext
; /* Next in a list */
105 int id
; /* Id of this Blob */
106 int seq
; /* Sequence number */
107 int sz
; /* Size of this Blob in bytes */
108 unsigned char a
[1]; /* Blob content. Extra space allocated as needed. */
112 ** Maximum number of files in the in-memory virtual filesystem.
117 ** Maximum allowed file size
119 #define MX_FILE_SZ 10000000
122 ** All global variables are gathered into the "g" singleton.
124 static struct GlobalVars
{
125 const char *zArgv0
; /* Name of program */
126 VFile aFile
[MX_FILE
]; /* The virtual filesystem */
127 int nDb
; /* Number of template databases */
128 Blob
*pFirstDb
; /* Content of first template database */
129 int nSql
; /* Number of SQL scripts */
130 Blob
*pFirstSql
; /* First SQL script */
131 char zTestName
[100]; /* Name of current test */
135 ** Print an error message and quit.
137 static void fatalError(const char *zFormat
, ...){
139 if( g
.zTestName
[0] ){
140 fprintf(stderr
, "%s (%s): ", g
.zArgv0
, g
.zTestName
);
142 fprintf(stderr
, "%s: ", g
.zArgv0
);
144 va_start(ap
, zFormat
);
145 vfprintf(stderr
, zFormat
, ap
);
147 fprintf(stderr
, "\n");
155 static void timeoutHandler(int NotUsed
){
157 fatalError("timeout\n");
162 ** Set the an alarm to go off after N seconds. Disable the alarm
165 static void setAlarm(int N
){
173 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
175 ** This an SQL progress handler. After an SQL statement has run for
176 ** many steps, we want to interrupt it. This guards against infinite
177 ** loops from recursive common table expressions.
179 ** *pVdbeLimitFlag is true if the --limit-vdbe command-line option is used.
180 ** In that case, hitting the progress handler is a fatal error.
182 static int progressHandler(void *pVdbeLimitFlag
){
183 if( *(int*)pVdbeLimitFlag
) fatalError("too many VDBE cycles");
189 ** Reallocate memory. Show and error and quit if unable.
191 static void *safe_realloc(void *pOld
, int szNew
){
192 void *pNew
= realloc(pOld
, szNew
<=0 ? 1 : szNew
);
193 if( pNew
==0 ) fatalError("unable to realloc for %d bytes", szNew
);
198 ** Initialize the virtual file system.
200 static void formatVfs(void){
202 for(i
=0; i
<MX_FILE
; i
++){
204 g
.aFile
[i
].zFilename
= 0;
212 ** Erase all information in the virtual file system.
214 static void reformatVfs(void){
216 for(i
=0; i
<MX_FILE
; i
++){
217 if( g
.aFile
[i
].sz
<0 ) continue;
218 if( g
.aFile
[i
].zFilename
){
219 free(g
.aFile
[i
].zFilename
);
220 g
.aFile
[i
].zFilename
= 0;
222 if( g
.aFile
[i
].nRef
>0 ){
223 fatalError("file %d still open. nRef=%d", i
, g
.aFile
[i
].nRef
);
233 ** Find a VFile by name
235 static VFile
*findVFile(const char *zName
){
237 if( zName
==0 ) return 0;
238 for(i
=0; i
<MX_FILE
; i
++){
239 if( g
.aFile
[i
].zFilename
==0 ) continue;
240 if( strcmp(g
.aFile
[i
].zFilename
, zName
)==0 ) return &g
.aFile
[i
];
246 ** Find a VFile by name. Create it if it does not already exist and
247 ** initialize it to the size and content given.
249 ** Return NULL only if the filesystem is full.
251 static VFile
*createVFile(const char *zName
, int sz
, unsigned char *pData
){
252 VFile
*pNew
= findVFile(zName
);
254 if( pNew
) return pNew
;
255 for(i
=0; i
<MX_FILE
&& g
.aFile
[i
].sz
>=0; i
++){}
256 if( i
>=MX_FILE
) return 0;
259 int nName
= (int)strlen(zName
)+1;
260 pNew
->zFilename
= safe_realloc(0, nName
);
261 memcpy(pNew
->zFilename
, zName
, nName
);
267 pNew
->a
= safe_realloc(0, sz
);
268 if( sz
>0 ) memcpy(pNew
->a
, pData
, sz
);
274 ** Implementation of the "readfile(X)" SQL function. The entire content
275 ** of the file named X is read and returned as a BLOB. NULL is returned
276 ** if the file does not exist or is unreadable.
278 static void readfileFunc(
279 sqlite3_context
*context
,
288 zName
= (const char*)sqlite3_value_text(argv
[0]);
289 if( zName
==0 ) return;
290 in
= fopen(zName
, "rb");
292 fseek(in
, 0, SEEK_END
);
295 pBuf
= sqlite3_malloc64( nIn
);
296 if( pBuf
&& 1==fread(pBuf
, nIn
, 1, in
) ){
297 sqlite3_result_blob(context
, pBuf
, nIn
, sqlite3_free
);
305 ** Implementation of the "writefile(X,Y)" SQL function. The argument Y
306 ** is written into file X. The number of bytes written is returned. Or
307 ** NULL is returned if something goes wrong, such as being unable to open
308 ** file X for writing.
310 static void writefileFunc(
311 sqlite3_context
*context
,
321 zFile
= (const char*)sqlite3_value_text(argv
[0]);
322 if( zFile
==0 ) return;
323 out
= fopen(zFile
, "wb");
325 z
= (const char*)sqlite3_value_blob(argv
[1]);
329 rc
= fwrite(z
, 1, sqlite3_value_bytes(argv
[1]), out
);
332 sqlite3_result_int64(context
, rc
);
337 ** Load a list of Blob objects from the database
339 static void blobListLoadFromDb(
340 sqlite3
*db
, /* Read from this database */
341 const char *zSql
, /* Query used to extract the blobs */
342 int onlyId
, /* Only load where id is this value */
343 int *pN
, /* OUT: Write number of blobs loaded here */
344 Blob
**ppList
/* OUT: Write the head of the blob list here */
354 z2
= sqlite3_mprintf("%s WHERE rowid=%d", zSql
, onlyId
);
356 z2
= sqlite3_mprintf("%s", zSql
);
358 rc
= sqlite3_prepare_v2(db
, z2
, -1, &pStmt
, 0);
360 if( rc
) fatalError("%s", sqlite3_errmsg(db
));
363 while( SQLITE_ROW
==sqlite3_step(pStmt
) ){
364 int sz
= sqlite3_column_bytes(pStmt
, 1);
365 Blob
*pNew
= safe_realloc(0, sizeof(*pNew
)+sz
);
366 pNew
->id
= sqlite3_column_int(pStmt
, 0);
370 memcpy(pNew
->a
, sqlite3_column_blob(pStmt
,1), sz
);
375 sqlite3_finalize(pStmt
);
377 *ppList
= head
.pNext
;
381 ** Free a list of Blob objects
383 static void blobListFree(Blob
*p
){
393 /* Return the current wall-clock time */
394 static sqlite3_int64
timeOfDay(void){
395 static sqlite3_vfs
*clockVfs
= 0;
397 if( clockVfs
==0 ) clockVfs
= sqlite3_vfs_find(0);
398 if( clockVfs
->iVersion
>=1 && clockVfs
->xCurrentTimeInt64
!=0 ){
399 clockVfs
->xCurrentTimeInt64(clockVfs
, &t
);
402 clockVfs
->xCurrentTime(clockVfs
, &r
);
403 t
= (sqlite3_int64
)(r
*86400000.0);
408 /* Methods for the VHandle object
410 static int inmemClose(sqlite3_file
*pFile
){
411 VHandle
*p
= (VHandle
*)pFile
;
412 VFile
*pVFile
= p
->pVFile
;
414 if( pVFile
->nRef
==0 && pVFile
->zFilename
==0 ){
421 static int inmemRead(
422 sqlite3_file
*pFile
, /* Read from this open file */
423 void *pData
, /* Store content in this buffer */
424 int iAmt
, /* Bytes of content */
425 sqlite3_int64 iOfst
/* Start reading here */
427 VHandle
*pHandle
= (VHandle
*)pFile
;
428 VFile
*pVFile
= pHandle
->pVFile
;
429 if( iOfst
<0 || iOfst
>=pVFile
->sz
){
430 memset(pData
, 0, iAmt
);
431 return SQLITE_IOERR_SHORT_READ
;
433 if( iOfst
+iAmt
>pVFile
->sz
){
434 memset(pData
, 0, iAmt
);
435 iAmt
= (int)(pVFile
->sz
- iOfst
);
436 memcpy(pData
, pVFile
->a
, iAmt
);
437 return SQLITE_IOERR_SHORT_READ
;
439 memcpy(pData
, pVFile
->a
+ iOfst
, iAmt
);
442 static int inmemWrite(
443 sqlite3_file
*pFile
, /* Write to this file */
444 const void *pData
, /* Content to write */
445 int iAmt
, /* bytes to write */
446 sqlite3_int64 iOfst
/* Start writing here */
448 VHandle
*pHandle
= (VHandle
*)pFile
;
449 VFile
*pVFile
= pHandle
->pVFile
;
450 if( iOfst
+iAmt
> pVFile
->sz
){
451 if( iOfst
+iAmt
>= MX_FILE_SZ
){
454 pVFile
->a
= safe_realloc(pVFile
->a
, (int)(iOfst
+iAmt
));
455 if( iOfst
> pVFile
->sz
){
456 memset(pVFile
->a
+ pVFile
->sz
, 0, (int)(iOfst
- pVFile
->sz
));
458 pVFile
->sz
= (int)(iOfst
+ iAmt
);
460 memcpy(pVFile
->a
+ iOfst
, pData
, iAmt
);
463 static int inmemTruncate(sqlite3_file
*pFile
, sqlite3_int64 iSize
){
464 VHandle
*pHandle
= (VHandle
*)pFile
;
465 VFile
*pVFile
= pHandle
->pVFile
;
466 if( pVFile
->sz
>iSize
&& iSize
>=0 ) pVFile
->sz
= (int)iSize
;
469 static int inmemSync(sqlite3_file
*pFile
, int flags
){
472 static int inmemFileSize(sqlite3_file
*pFile
, sqlite3_int64
*pSize
){
473 *pSize
= ((VHandle
*)pFile
)->pVFile
->sz
;
476 static int inmemLock(sqlite3_file
*pFile
, int type
){
479 static int inmemUnlock(sqlite3_file
*pFile
, int type
){
482 static int inmemCheckReservedLock(sqlite3_file
*pFile
, int *pOut
){
486 static int inmemFileControl(sqlite3_file
*pFile
, int op
, void *pArg
){
487 return SQLITE_NOTFOUND
;
489 static int inmemSectorSize(sqlite3_file
*pFile
){
492 static int inmemDeviceCharacteristics(sqlite3_file
*pFile
){
494 SQLITE_IOCAP_SAFE_APPEND
|
495 SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
|
496 SQLITE_IOCAP_POWERSAFE_OVERWRITE
;
500 /* Method table for VHandle
502 static sqlite3_io_methods VHandleMethods
= {
504 /* xClose */ inmemClose
,
505 /* xRead */ inmemRead
,
506 /* xWrite */ inmemWrite
,
507 /* xTruncate */ inmemTruncate
,
508 /* xSync */ inmemSync
,
509 /* xFileSize */ inmemFileSize
,
510 /* xLock */ inmemLock
,
511 /* xUnlock */ inmemUnlock
,
512 /* xCheck... */ inmemCheckReservedLock
,
513 /* xFileCtrl */ inmemFileControl
,
514 /* xSectorSz */ inmemSectorSize
,
515 /* xDevchar */ inmemDeviceCharacteristics
,
525 ** Open a new file in the inmem VFS. All files are anonymous and are
528 static int inmemOpen(
530 const char *zFilename
,
535 VFile
*pVFile
= createVFile(zFilename
, 0, (unsigned char*)"");
536 VHandle
*pHandle
= (VHandle
*)pFile
;
540 pHandle
->pVFile
= pVFile
;
542 pFile
->pMethods
= &VHandleMethods
;
543 if( pOutFlags
) *pOutFlags
= openFlags
;
548 ** Delete a file by name
550 static int inmemDelete(
552 const char *zFilename
,
555 VFile
*pVFile
= findVFile(zFilename
);
556 if( pVFile
==0 ) return SQLITE_OK
;
557 if( pVFile
->nRef
==0 ){
558 free(pVFile
->zFilename
);
559 pVFile
->zFilename
= 0;
565 return SQLITE_IOERR_DELETE
;
568 /* Check for the existance of a file
570 static int inmemAccess(
572 const char *zFilename
,
576 VFile
*pVFile
= findVFile(zFilename
);
577 *pResOut
= pVFile
!=0;
581 /* Get the canonical pathname for a file
583 static int inmemFullPathname(
585 const char *zFilename
,
589 sqlite3_snprintf(nOut
, zOut
, "%s", zFilename
);
594 ** Register the VFS that reads from the g.aFile[] set of files.
596 static void inmemVfsRegister(void){
597 static sqlite3_vfs inmemVfs
;
598 sqlite3_vfs
*pDefault
= sqlite3_vfs_find(0);
599 inmemVfs
.iVersion
= 3;
600 inmemVfs
.szOsFile
= sizeof(VHandle
);
601 inmemVfs
.mxPathname
= 200;
602 inmemVfs
.zName
= "inmem";
603 inmemVfs
.xOpen
= inmemOpen
;
604 inmemVfs
.xDelete
= inmemDelete
;
605 inmemVfs
.xAccess
= inmemAccess
;
606 inmemVfs
.xFullPathname
= inmemFullPathname
;
607 inmemVfs
.xRandomness
= pDefault
->xRandomness
;
608 inmemVfs
.xSleep
= pDefault
->xSleep
;
609 inmemVfs
.xCurrentTimeInt64
= pDefault
->xCurrentTimeInt64
;
610 sqlite3_vfs_register(&inmemVfs
, 0);
614 ** Allowed values for the runFlags parameter to runSql()
616 #define SQL_TRACE 0x0001 /* Print each SQL statement as it is prepared */
617 #define SQL_OUTPUT 0x0002 /* Show the SQL output */
620 ** Run multiple commands of SQL. Similar to sqlite3_exec(), but does not
621 ** stop if an error is encountered.
623 static void runSql(sqlite3
*db
, const char *zSql
, unsigned runFlags
){
625 const char *zEnd
= &zSql
[strlen(zSql
)];
628 while( zSql
&& zSql
[0] ){
631 sqlite3_prepare_v2(db
, zSql
, -1, &pStmt
, &zMore
);
632 assert( zMore
<=zEnd
);
633 if( zMore
==zSql
) break;
634 if( runFlags
& SQL_TRACE
){
635 const char *z
= zSql
;
637 while( z
<zMore
&& ISSPACE(z
[0]) ) z
++;
638 n
= (int)(zMore
- z
);
639 while( n
>0 && ISSPACE(z
[n
-1]) ) n
--;
642 printf("TRACE: %.*s (error: %s)\n", n
, z
, sqlite3_errmsg(db
));
644 printf("TRACE: %.*s\n", n
, z
);
649 if( (runFlags
& SQL_OUTPUT
)==0 ){
650 while( SQLITE_ROW
==sqlite3_step(pStmt
) ){}
653 while( SQLITE_ROW
==sqlite3_step(pStmt
) ){
656 nCol
= sqlite3_column_count(pStmt
);
658 printf("--------------------------------------------\n");
660 for(i
=0; i
<nCol
; i
++){
661 int eType
= sqlite3_column_type(pStmt
,i
);
662 printf("%s = ", sqlite3_column_name(pStmt
,i
));
668 case SQLITE_INTEGER
: {
669 printf("INT %s\n", sqlite3_column_text(pStmt
,i
));
673 printf("FLOAT %s\n", sqlite3_column_text(pStmt
,i
));
677 printf("TEXT [%s]\n", sqlite3_column_text(pStmt
,i
));
681 printf("BLOB (%d bytes)\n", sqlite3_column_bytes(pStmt
,i
));
688 sqlite3_finalize(pStmt
);
694 ** Rebuild the database file.
696 ** (1) Remove duplicate entries
697 ** (2) Put all entries in order
700 static void rebuild_database(sqlite3
*db
){
702 rc
= sqlite3_exec(db
,
704 "CREATE TEMP TABLE dbx AS SELECT DISTINCT dbcontent FROM db;\n"
706 "INSERT INTO db(dbid, dbcontent) SELECT NULL, dbcontent FROM dbx ORDER BY 2;\n"
708 "CREATE TEMP TABLE sx AS SELECT DISTINCT sqltext FROM xsql;\n"
709 "DELETE FROM xsql;\n"
710 "INSERT INTO xsql(sqlid,sqltext) SELECT NULL, sqltext FROM sx ORDER BY 2;\n"
713 "PRAGMA page_size=1024;\n"
714 "VACUUM;\n", 0, 0, 0);
715 if( rc
) fatalError("cannot rebuild: %s", sqlite3_errmsg(db
));
719 ** Return the value of a hexadecimal digit. Return -1 if the input
720 ** is not a hex digit.
722 static int hexDigitValue(char c
){
723 if( c
>='0' && c
<='9' ) return c
- '0';
724 if( c
>='a' && c
<='f' ) return c
- 'a' + 10;
725 if( c
>='A' && c
<='F' ) return c
- 'A' + 10;
730 ** Interpret zArg as an integer value, possibly with suffixes.
732 static int integerValue(const char *zArg
){
734 static const struct { char *zSuffix
; int iMult
; } aMult
[] = {
736 { "MiB", 1024*1024 },
737 { "GiB", 1024*1024*1024 },
740 { "GB", 1000000000 },
750 }else if( zArg
[0]=='+' ){
753 if( zArg
[0]=='0' && zArg
[1]=='x' ){
756 while( (x
= hexDigitValue(zArg
[0]))>=0 ){
761 while( ISDIGIT(zArg
[0]) ){
762 v
= v
*10 + zArg
[0] - '0';
766 for(i
=0; i
<sizeof(aMult
)/sizeof(aMult
[0]); i
++){
767 if( sqlite3_stricmp(aMult
[i
].zSuffix
, zArg
)==0 ){
772 if( v
>0x7fffffff ) fatalError("parameter too large - max 2147483648");
773 return (int)(isNeg
? -v
: v
);
777 ** Print sketchy documentation for this utility program
779 static void showHelp(void){
780 printf("Usage: %s [options] SOURCE-DB ?ARGS...?\n", g
.zArgv0
);
782 "Read databases and SQL scripts from SOURCE-DB and execute each script against\n"
783 "each database, checking for crashes and memory leaks.\n"
785 " --cell-size-check Set the PRAGMA cell_size_check=ON\n"
786 " --dbid N Use only the database where dbid=N\n"
787 " --export-db DIR Write databases to files(s) in DIR. Works with --dbid\n"
788 " --export-sql DIR Write SQL to file(s) in DIR. Also works with --sqlid\n"
789 " --help Show this help text\n"
790 " -q|--quiet Reduced output\n"
791 " --limit-mem N Limit memory used by test SQLite instance to N bytes\n"
792 " --limit-vdbe Panic if any test runs for more than 100,000 cycles\n"
793 " --load-sql ARGS... Load SQL scripts fro files into SOURCE-DB\n"
794 " --load-db ARGS... Load template databases from files into SOURCE_DB\n"
795 " -m TEXT Add a description to the database\n"
796 " --native-vfs Use the native VFS for initially empty database files\n"
797 " --rebuild Rebuild and vacuum the database file\n"
798 " --result-trace Show the results of each SQL command\n"
799 " --sqlid N Use only SQL where sqlid=N\n"
800 " --timeout N Abort if any single test needs more than N seconds\n"
801 " -v|--verbose Increased output. Repeat for more output.\n"
805 int main(int argc
, char **argv
){
806 sqlite3_int64 iBegin
; /* Start time of this program */
807 int quietFlag
= 0; /* True if --quiet or -q */
808 int verboseFlag
= 0; /* True if --verbose or -v */
809 char *zInsSql
= 0; /* SQL statement for --load-db or --load-sql */
810 int iFirstInsArg
= 0; /* First argv[] to use for --load-db or --load-sql */
811 sqlite3
*db
= 0; /* The open database connection */
812 sqlite3_stmt
*pStmt
; /* A prepared statement */
813 int rc
; /* Result code from SQLite interface calls */
814 Blob
*pSql
; /* For looping over SQL scripts */
815 Blob
*pDb
; /* For looping over template databases */
816 int i
; /* Loop index for the argv[] loop */
817 int onlySqlid
= -1; /* --sqlid */
818 int onlyDbid
= -1; /* --dbid */
819 int nativeFlag
= 0; /* --native-vfs */
820 int rebuildFlag
= 0; /* --rebuild */
821 int vdbeLimitFlag
= 0; /* --limit-vdbe */
822 int timeoutTest
= 0; /* undocumented --timeout-test flag */
823 int runFlags
= 0; /* Flags sent to runSql() */
824 char *zMsg
= 0; /* Add this message */
825 int nSrcDb
= 0; /* Number of source databases */
826 char **azSrcDb
= 0; /* Array of source database names */
827 int iSrcDb
; /* Loop over all source databases */
828 int nTest
= 0; /* Total number of tests performed */
829 char *zDbName
= ""; /* Appreviated name of a source database */
830 const char *zFailCode
= 0; /* Value of the TEST_FAILURE environment variable */
831 int cellSzCkFlag
= 0; /* --cell-size-check */
832 int sqlFuzz
= 0; /* True for SQL fuzz testing. False for DB fuzz */
833 int iTimeout
= 120; /* Default 120-second timeout */
834 int nMem
= 0; /* Memory limit */
835 char *zExpDb
= 0; /* Write Databases to files in this directory */
836 char *zExpSql
= 0; /* Write SQL to files in this directory */
837 void *pHeap
= 0; /* Heap for use by SQLite */
839 iBegin
= timeOfDay();
841 signal(SIGALRM
, timeoutHandler
);
844 zFailCode
= getenv("TEST_FAILURE");
845 for(i
=1; i
<argc
; i
++){
846 const char *z
= argv
[i
];
850 if( strcmp(z
,"cell-size-check")==0 ){
853 if( strcmp(z
,"dbid")==0 ){
854 if( i
>=argc
-1 ) fatalError("missing arguments on %s", argv
[i
]);
855 onlyDbid
= integerValue(argv
[++i
]);
857 if( strcmp(z
,"export-db")==0 ){
858 if( i
>=argc
-1 ) fatalError("missing arguments on %s", argv
[i
]);
861 if( strcmp(z
,"export-sql")==0 ){
862 if( i
>=argc
-1 ) fatalError("missing arguments on %s", argv
[i
]);
865 if( strcmp(z
,"help")==0 ){
869 if( strcmp(z
,"limit-mem")==0 ){
870 #if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5)
871 fatalError("the %s option requires -DSQLITE_ENABLE_MEMSYS5 or _MEMSYS3",
874 if( i
>=argc
-1 ) fatalError("missing arguments on %s", argv
[i
]);
875 nMem
= integerValue(argv
[++i
]);
878 if( strcmp(z
,"limit-vdbe")==0 ){
881 if( strcmp(z
,"load-sql")==0 ){
882 zInsSql
= "INSERT INTO xsql(sqltext) VALUES(CAST(readfile(?1) AS text))";
886 if( strcmp(z
,"load-db")==0 ){
887 zInsSql
= "INSERT INTO db(dbcontent) VALUES(readfile(?1))";
891 if( strcmp(z
,"m")==0 ){
892 if( i
>=argc
-1 ) fatalError("missing arguments on %s", argv
[i
]);
895 if( strcmp(z
,"native-vfs")==0 ){
898 if( strcmp(z
,"quiet")==0 || strcmp(z
,"q")==0 ){
902 if( strcmp(z
,"rebuild")==0 ){
905 if( strcmp(z
,"result-trace")==0 ){
906 runFlags
|= SQL_OUTPUT
;
908 if( strcmp(z
,"sqlid")==0 ){
909 if( i
>=argc
-1 ) fatalError("missing arguments on %s", argv
[i
]);
910 onlySqlid
= integerValue(argv
[++i
]);
912 if( strcmp(z
,"timeout")==0 ){
913 if( i
>=argc
-1 ) fatalError("missing arguments on %s", argv
[i
]);
914 iTimeout
= integerValue(argv
[++i
]);
916 if( strcmp(z
,"timeout-test")==0 ){
919 fatalError("timeout is not available on non-unix systems");
922 if( strcmp(z
,"verbose")==0 || strcmp(z
,"v")==0 ){
925 if( verboseFlag
>1 ) runFlags
|= SQL_TRACE
;
928 fatalError("unknown option: %s", argv
[i
]);
932 azSrcDb
= safe_realloc(azSrcDb
, nSrcDb
*sizeof(azSrcDb
[0]));
933 azSrcDb
[nSrcDb
-1] = argv
[i
];
936 if( nSrcDb
==0 ) fatalError("no source database specified");
939 fatalError("cannot change the description of more than one database");
942 fatalError("cannot import into more than one database");
946 /* Process each source database separately */
947 for(iSrcDb
=0; iSrcDb
<nSrcDb
; iSrcDb
++){
948 rc
= sqlite3_open(azSrcDb
[iSrcDb
], &db
);
950 fatalError("cannot open source database %s - %s",
951 azSrcDb
[iSrcDb
], sqlite3_errmsg(db
));
953 rc
= sqlite3_exec(db
,
954 "CREATE TABLE IF NOT EXISTS db(\n"
955 " dbid INTEGER PRIMARY KEY, -- database id\n"
956 " dbcontent BLOB -- database disk file image\n"
958 "CREATE TABLE IF NOT EXISTS xsql(\n"
959 " sqlid INTEGER PRIMARY KEY, -- SQL script id\n"
960 " sqltext TEXT -- Text of SQL statements to run\n"
962 "CREATE TABLE IF NOT EXISTS readme(\n"
963 " msg TEXT -- Human-readable description of this file\n"
965 if( rc
) fatalError("cannot create schema: %s", sqlite3_errmsg(db
));
968 zSql
= sqlite3_mprintf(
969 "DELETE FROM readme; INSERT INTO readme(msg) VALUES(%Q)", zMsg
);
970 rc
= sqlite3_exec(db
, zSql
, 0, 0, 0);
972 if( rc
) fatalError("cannot change description: %s", sqlite3_errmsg(db
));
975 sqlite3_create_function(db
, "readfile", 1, SQLITE_UTF8
, 0,
977 rc
= sqlite3_prepare_v2(db
, zInsSql
, -1, &pStmt
, 0);
978 if( rc
) fatalError("cannot prepare statement [%s]: %s",
979 zInsSql
, sqlite3_errmsg(db
));
980 rc
= sqlite3_exec(db
, "BEGIN", 0, 0, 0);
981 if( rc
) fatalError("cannot start a transaction");
982 for(i
=iFirstInsArg
; i
<argc
; i
++){
983 sqlite3_bind_text(pStmt
, 1, argv
[i
], -1, SQLITE_STATIC
);
985 rc
= sqlite3_reset(pStmt
);
986 if( rc
) fatalError("insert failed for %s", argv
[i
]);
988 sqlite3_finalize(pStmt
);
989 rc
= sqlite3_exec(db
, "COMMIT", 0, 0, 0);
990 if( rc
) fatalError("cannot commit the transaction: %s", sqlite3_errmsg(db
));
991 rebuild_database(db
);
995 if( zExpDb
!=0 || zExpSql
!=0 ){
996 sqlite3_create_function(db
, "writefile", 2, SQLITE_UTF8
, 0,
997 writefileFunc
, 0, 0);
1000 "SELECT writefile(printf('%s/db%06d.db',?1,dbid),dbcontent),"
1001 " dbid, printf('%s/db%06d.db',?1,dbid), length(dbcontent)"
1002 " FROM db WHERE ?2<0 OR dbid=?2;";
1003 rc
= sqlite3_prepare_v2(db
, zExDb
, -1, &pStmt
, 0);
1004 if( rc
) fatalError("cannot prepare statement [%s]: %s",
1005 zExDb
, sqlite3_errmsg(db
));
1006 sqlite3_bind_text64(pStmt
, 1, zExpDb
, strlen(zExpDb
),
1007 SQLITE_STATIC
, SQLITE_UTF8
);
1008 sqlite3_bind_int(pStmt
, 2, onlyDbid
);
1009 while( sqlite3_step(pStmt
)==SQLITE_ROW
){
1010 printf("write db-%d (%d bytes) into %s\n",
1011 sqlite3_column_int(pStmt
,1),
1012 sqlite3_column_int(pStmt
,3),
1013 sqlite3_column_text(pStmt
,2));
1015 sqlite3_finalize(pStmt
);
1018 const char *zExSql
=
1019 "SELECT writefile(printf('%s/sql%06d.txt',?1,sqlid),sqltext),"
1020 " sqlid, printf('%s/sql%06d.txt',?1,sqlid), length(sqltext)"
1021 " FROM xsql WHERE ?2<0 OR sqlid=?2;";
1022 rc
= sqlite3_prepare_v2(db
, zExSql
, -1, &pStmt
, 0);
1023 if( rc
) fatalError("cannot prepare statement [%s]: %s",
1024 zExSql
, sqlite3_errmsg(db
));
1025 sqlite3_bind_text64(pStmt
, 1, zExpSql
, strlen(zExpSql
),
1026 SQLITE_STATIC
, SQLITE_UTF8
);
1027 sqlite3_bind_int(pStmt
, 2, onlySqlid
);
1028 while( sqlite3_step(pStmt
)==SQLITE_ROW
){
1029 printf("write sql-%d (%d bytes) into %s\n",
1030 sqlite3_column_int(pStmt
,1),
1031 sqlite3_column_int(pStmt
,3),
1032 sqlite3_column_text(pStmt
,2));
1034 sqlite3_finalize(pStmt
);
1040 /* Load all SQL script content and all initial database images from the
1043 blobListLoadFromDb(db
, "SELECT sqlid, sqltext FROM xsql", onlySqlid
,
1044 &g
.nSql
, &g
.pFirstSql
);
1045 if( g
.nSql
==0 ) fatalError("need at least one SQL script");
1046 blobListLoadFromDb(db
, "SELECT dbid, dbcontent FROM db", onlyDbid
,
1047 &g
.nDb
, &g
.pFirstDb
);
1049 g
.pFirstDb
= safe_realloc(0, sizeof(Blob
));
1050 memset(g
.pFirstDb
, 0, sizeof(Blob
));
1052 g
.pFirstDb
->seq
= 0;
1057 /* Print the description, if there is one */
1059 zDbName
= azSrcDb
[iSrcDb
];
1060 i
= (int)strlen(zDbName
) - 1;
1061 while( i
>0 && zDbName
[i
-1]!='/' && zDbName
[i
-1]!='\\' ){ i
--; }
1063 sqlite3_prepare_v2(db
, "SELECT msg FROM readme", -1, &pStmt
, 0);
1064 if( pStmt
&& sqlite3_step(pStmt
)==SQLITE_ROW
){
1065 printf("%s: %s\n", zDbName
, sqlite3_column_text(pStmt
,0));
1067 sqlite3_finalize(pStmt
);
1070 /* Rebuild the database, if requested */
1073 printf("%s: rebuilding... ", zDbName
);
1076 rebuild_database(db
);
1077 if( !quietFlag
) printf("done\n");
1080 /* Close the source database. Verify that no SQLite memory allocations are
1084 if( sqlite3_memory_used()>0 ){
1085 fatalError("SQLite has memory in use before the start of testing");
1088 /* Limit available memory, if requested */
1091 pHeap
= malloc(nMem
);
1093 fatalError("failed to allocate %d bytes of heap memory", nMem
);
1095 sqlite3_config(SQLITE_CONFIG_HEAP
, pHeap
, nMem
, 128);
1098 /* Register the in-memory virtual filesystem
1103 /* Run a test using each SQL script against each database.
1105 if( !verboseFlag
&& !quietFlag
) printf("%s:", zDbName
);
1106 for(pSql
=g
.pFirstSql
; pSql
; pSql
=pSql
->pNext
){
1107 for(pDb
=g
.pFirstDb
; pDb
; pDb
=pDb
->pNext
){
1109 const char *zVfs
= "inmem";
1110 sqlite3_snprintf(sizeof(g
.zTestName
), g
.zTestName
, "sqlid=%d,dbid=%d",
1113 printf("%s\n", g
.zTestName
);
1115 }else if( !quietFlag
){
1116 static int prevAmt
= -1;
1117 int idx
= pSql
->seq
*g
.nDb
+ pDb
->id
- 1;
1118 int amt
= idx
*10/(g
.nDb
*g
.nSql
);
1120 printf(" %d%%", amt
*10);
1125 createVFile("main.db", pDb
->sz
, pDb
->a
);
1126 openFlags
= SQLITE_OPEN_CREATE
| SQLITE_OPEN_READWRITE
;
1127 if( nativeFlag
&& pDb
->sz
==0 ){
1128 openFlags
|= SQLITE_OPEN_MEMORY
;
1131 rc
= sqlite3_open_v2("main.db", &db
, openFlags
, zVfs
);
1132 if( rc
) fatalError("cannot open inmem database");
1133 if( cellSzCkFlag
) runSql(db
, "PRAGMA cell_size_check=ON", runFlags
);
1135 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
1136 if( sqlFuzz
|| vdbeLimitFlag
){
1137 sqlite3_progress_handler(db
, 100000, progressHandler
, &vdbeLimitFlag
);
1141 runSql(db
, (char*)pSql
->a
, runFlags
);
1142 }while( timeoutTest
);
1145 if( sqlite3_memory_used()>0 ) fatalError("memory leak");
1150 /* Simulate an error if the TEST_FAILURE environment variable is "5".
1151 ** This is used to verify that automated test script really do spot
1152 ** errors that occur in this test program.
1155 if( zFailCode
[0]=='5' && zFailCode
[1]==0 ){
1156 fatalError("simulated failure");
1157 }else if( zFailCode
[0]!=0 ){
1158 /* If TEST_FAILURE is something other than 5, just exit the test
1160 printf("\nExit early due to TEST_FAILURE being set\n");
1162 goto sourcedb_cleanup
;
1167 if( !quietFlag
&& !verboseFlag
){
1168 printf(" 100%% - %d tests\n", g
.nDb
*g
.nSql
);
1171 /* Clean up at the end of processing a single source database
1174 blobListFree(g
.pFirstSql
);
1175 blobListFree(g
.pFirstDb
);
1178 } /* End loop over all source databases */
1181 sqlite3_int64 iElapse
= timeOfDay() - iBegin
;
1182 printf("fuzzcheck: 0 errors out of %d tests in %d.%03d seconds\n"
1184 nTest
, (int)(iElapse
/1000), (int)(iElapse
%1000),
1185 sqlite3_libversion(), sqlite3_sourceid());