OLD | NEW |
| (Empty) |
1 /* | |
2 ** 2015-04-17 | |
3 ** | |
4 ** The author disclaims copyright to this source code. In place of | |
5 ** a legal notice, here is a blessing: | |
6 ** | |
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. | |
10 ** | |
11 ************************************************************************* | |
12 ** | |
13 ** This is a utility program designed to aid running the SQLite library | |
14 ** against an external fuzzer, such as American Fuzzy Lop (AFL) | |
15 ** (http://lcamtuf.coredump.cx/afl/). Basically, this program reads | |
16 ** SQL text from standard input and passes it through to SQLite for evaluation, | |
17 ** just like the "sqlite3" command-line shell. Differences from the | |
18 ** command-line shell: | |
19 ** | |
20 ** (1) The complex "dot-command" extensions are omitted. This | |
21 ** prevents the fuzzer from discovering that it can run things | |
22 ** like ".shell rm -rf ~" | |
23 ** | |
24 ** (2) The database is opened with the SQLITE_OPEN_MEMORY flag so that | |
25 ** no disk I/O from the database is permitted. The ATTACH command | |
26 ** with a filename still uses an in-memory database. | |
27 ** | |
28 ** (3) The main in-memory database can be initialized from a template | |
29 ** disk database so that the fuzzer starts with a database containing | |
30 ** content. | |
31 ** | |
32 ** (4) The eval() SQL function is added, allowing the fuzzer to do | |
33 ** interesting recursive operations. | |
34 ** | |
35 ** (5) An error is raised if there is a memory leak. | |
36 ** | |
37 ** The input text can be divided into separate test cases using comments | |
38 ** of the form: | |
39 ** | |
40 ** |****<...>****| | |
41 ** | |
42 ** where the "..." is arbitrary text. (Except the "|" should really be "/". | |
43 ** "|" is used here to avoid compiler errors about nested comments.) | |
44 ** A separate in-memory SQLite database is created to run each test case. | |
45 ** This feature allows the "queue" of AFL to be captured into a single big | |
46 ** file using a command like this: | |
47 ** | |
48 ** (for i in id:*; do echo '|****<'$i'>****|'; cat $i; done) >~/all-queue.txt | |
49 ** | |
50 ** (Once again, change the "|" to "/") Then all elements of the AFL queue | |
51 ** can be run in a single go (for regression testing, for example) by typing: | |
52 ** | |
53 ** fuzzershell -f ~/all-queue.txt | |
54 ** | |
55 ** After running each chunk of SQL, the database connection is closed. The | |
56 ** program aborts if the close fails or if there is any unfreed memory after | |
57 ** the close. | |
58 ** | |
59 ** New test cases can be appended to all-queue.txt at any time. If redundant | |
60 ** test cases are added, they can be eliminated by running: | |
61 ** | |
62 ** fuzzershell -f ~/all-queue.txt --unique-cases ~/unique-cases.txt | |
63 */ | |
64 #include <stdio.h> | |
65 #include <stdlib.h> | |
66 #include <string.h> | |
67 #include <stdarg.h> | |
68 #include <ctype.h> | |
69 #include "sqlite3.h" | |
70 #define ISDIGIT(X) isdigit((unsigned char)(X)) | |
71 | |
72 /* | |
73 ** All global variables are gathered into the "g" singleton. | |
74 */ | |
75 struct GlobalVars { | |
76 const char *zArgv0; /* Name of program */ | |
77 sqlite3_mem_methods sOrigMem; /* Original memory methods */ | |
78 sqlite3_mem_methods sOomMem; /* Memory methods with OOM simulator */ | |
79 int iOomCntdown; /* Memory fails on 1 to 0 transition */ | |
80 int nOomFault; /* Increments for each OOM fault */ | |
81 int bOomOnce; /* Fail just once if true */ | |
82 int bOomEnable; /* True to enable OOM simulation */ | |
83 int nOomBrkpt; /* Number of calls to oomFault() */ | |
84 char zTestName[100]; /* Name of current test */ | |
85 } g; | |
86 | |
87 /* | |
88 ** Maximum number of iterations for an OOM test | |
89 */ | |
90 #ifndef OOM_MAX | |
91 # define OOM_MAX 625 | |
92 #endif | |
93 | |
94 /* | |
95 ** This routine is called when a simulated OOM occurs. It exists as a | |
96 ** convenient place to set a debugger breakpoint. | |
97 */ | |
98 static void oomFault(void){ | |
99 g.nOomBrkpt++; /* Prevent oomFault() from being optimized out */ | |
100 } | |
101 | |
102 | |
103 /* Versions of malloc() and realloc() that simulate OOM conditions */ | |
104 static void *oomMalloc(int nByte){ | |
105 if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){ | |
106 g.iOomCntdown--; | |
107 if( g.iOomCntdown==0 ){ | |
108 if( g.nOomFault==0 ) oomFault(); | |
109 g.nOomFault++; | |
110 if( !g.bOomOnce ) g.iOomCntdown = 1; | |
111 return 0; | |
112 } | |
113 } | |
114 return g.sOrigMem.xMalloc(nByte); | |
115 } | |
116 static void *oomRealloc(void *pOld, int nByte){ | |
117 if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){ | |
118 g.iOomCntdown--; | |
119 if( g.iOomCntdown==0 ){ | |
120 if( g.nOomFault==0 ) oomFault(); | |
121 g.nOomFault++; | |
122 if( !g.bOomOnce ) g.iOomCntdown = 1; | |
123 return 0; | |
124 } | |
125 } | |
126 return g.sOrigMem.xRealloc(pOld, nByte); | |
127 } | |
128 | |
129 /* | |
130 ** Print an error message and abort in such a way to indicate to the | |
131 ** fuzzer that this counts as a crash. | |
132 */ | |
133 static void abendError(const char *zFormat, ...){ | |
134 va_list ap; | |
135 if( g.zTestName[0] ){ | |
136 fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName); | |
137 }else{ | |
138 fprintf(stderr, "%s: ", g.zArgv0); | |
139 } | |
140 va_start(ap, zFormat); | |
141 vfprintf(stderr, zFormat, ap); | |
142 va_end(ap); | |
143 fprintf(stderr, "\n"); | |
144 abort(); | |
145 } | |
146 /* | |
147 ** Print an error message and quit, but not in a way that would look | |
148 ** like a crash. | |
149 */ | |
150 static void fatalError(const char *zFormat, ...){ | |
151 va_list ap; | |
152 if( g.zTestName[0] ){ | |
153 fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName); | |
154 }else{ | |
155 fprintf(stderr, "%s: ", g.zArgv0); | |
156 } | |
157 va_start(ap, zFormat); | |
158 vfprintf(stderr, zFormat, ap); | |
159 va_end(ap); | |
160 fprintf(stderr, "\n"); | |
161 exit(1); | |
162 } | |
163 | |
164 /* | |
165 ** Evaluate some SQL. Abort if unable. | |
166 */ | |
167 static void sqlexec(sqlite3 *db, const char *zFormat, ...){ | |
168 va_list ap; | |
169 char *zSql; | |
170 char *zErrMsg = 0; | |
171 int rc; | |
172 va_start(ap, zFormat); | |
173 zSql = sqlite3_vmprintf(zFormat, ap); | |
174 va_end(ap); | |
175 rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg); | |
176 if( rc ) abendError("failed sql [%s]: %s", zSql, zErrMsg); | |
177 sqlite3_free(zSql); | |
178 } | |
179 | |
180 /* | |
181 ** This callback is invoked by sqlite3_log(). | |
182 */ | |
183 static void shellLog(void *pNotUsed, int iErrCode, const char *zMsg){ | |
184 printf("LOG: (%d) %s\n", iErrCode, zMsg); | |
185 fflush(stdout); | |
186 } | |
187 static void shellLogNoop(void *pNotUsed, int iErrCode, const char *zMsg){ | |
188 return; | |
189 } | |
190 | |
191 /* | |
192 ** This callback is invoked by sqlite3_exec() to return query results. | |
193 */ | |
194 static int execCallback(void *NotUsed, int argc, char **argv, char **colv){ | |
195 int i; | |
196 static unsigned cnt = 0; | |
197 printf("ROW #%u:\n", ++cnt); | |
198 for(i=0; i<argc; i++){ | |
199 printf(" %s=", colv[i]); | |
200 if( argv[i] ){ | |
201 printf("[%s]\n", argv[i]); | |
202 }else{ | |
203 printf("NULL\n"); | |
204 } | |
205 } | |
206 fflush(stdout); | |
207 return 0; | |
208 } | |
209 static int execNoop(void *NotUsed, int argc, char **argv, char **colv){ | |
210 return 0; | |
211 } | |
212 | |
213 #ifndef SQLITE_OMIT_TRACE | |
214 /* | |
215 ** This callback is invoked by sqlite3_trace() as each SQL statement | |
216 ** starts. | |
217 */ | |
218 static void traceCallback(void *NotUsed, const char *zMsg){ | |
219 printf("TRACE: %s\n", zMsg); | |
220 fflush(stdout); | |
221 } | |
222 static void traceNoop(void *NotUsed, const char *zMsg){ | |
223 return; | |
224 } | |
225 #endif | |
226 | |
227 /*************************************************************************** | |
228 ** eval() implementation copied from ../ext/misc/eval.c | |
229 */ | |
230 /* | |
231 ** Structure used to accumulate the output | |
232 */ | |
233 struct EvalResult { | |
234 char *z; /* Accumulated output */ | |
235 const char *zSep; /* Separator */ | |
236 int szSep; /* Size of the separator string */ | |
237 sqlite3_int64 nAlloc; /* Number of bytes allocated for z[] */ | |
238 sqlite3_int64 nUsed; /* Number of bytes of z[] actually used */ | |
239 }; | |
240 | |
241 /* | |
242 ** Callback from sqlite_exec() for the eval() function. | |
243 */ | |
244 static int callback(void *pCtx, int argc, char **argv, char **colnames){ | |
245 struct EvalResult *p = (struct EvalResult*)pCtx; | |
246 int i; | |
247 for(i=0; i<argc; i++){ | |
248 const char *z = argv[i] ? argv[i] : ""; | |
249 size_t sz = strlen(z); | |
250 if( (sqlite3_int64)sz+p->nUsed+p->szSep+1 > p->nAlloc ){ | |
251 char *zNew; | |
252 p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; | |
253 /* Using sqlite3_realloc64() would be better, but it is a recent | |
254 ** addition and will cause a segfault if loaded by an older version | |
255 ** of SQLite. */ | |
256 zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0; | |
257 if( zNew==0 ){ | |
258 sqlite3_free(p->z); | |
259 memset(p, 0, sizeof(*p)); | |
260 return 1; | |
261 } | |
262 p->z = zNew; | |
263 } | |
264 if( p->nUsed>0 ){ | |
265 memcpy(&p->z[p->nUsed], p->zSep, p->szSep); | |
266 p->nUsed += p->szSep; | |
267 } | |
268 memcpy(&p->z[p->nUsed], z, sz); | |
269 p->nUsed += sz; | |
270 } | |
271 return 0; | |
272 } | |
273 | |
274 /* | |
275 ** Implementation of the eval(X) and eval(X,Y) SQL functions. | |
276 ** | |
277 ** Evaluate the SQL text in X. Return the results, using string | |
278 ** Y as the separator. If Y is omitted, use a single space character. | |
279 */ | |
280 static void sqlEvalFunc( | |
281 sqlite3_context *context, | |
282 int argc, | |
283 sqlite3_value **argv | |
284 ){ | |
285 const char *zSql; | |
286 sqlite3 *db; | |
287 char *zErr = 0; | |
288 int rc; | |
289 struct EvalResult x; | |
290 | |
291 memset(&x, 0, sizeof(x)); | |
292 x.zSep = " "; | |
293 zSql = (const char*)sqlite3_value_text(argv[0]); | |
294 if( zSql==0 ) return; | |
295 if( argc>1 ){ | |
296 x.zSep = (const char*)sqlite3_value_text(argv[1]); | |
297 if( x.zSep==0 ) return; | |
298 } | |
299 x.szSep = (int)strlen(x.zSep); | |
300 db = sqlite3_context_db_handle(context); | |
301 rc = sqlite3_exec(db, zSql, callback, &x, &zErr); | |
302 if( rc!=SQLITE_OK ){ | |
303 sqlite3_result_error(context, zErr, -1); | |
304 sqlite3_free(zErr); | |
305 }else if( x.zSep==0 ){ | |
306 sqlite3_result_error_nomem(context); | |
307 sqlite3_free(x.z); | |
308 }else{ | |
309 sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free); | |
310 } | |
311 } | |
312 /* End of the eval() implementation | |
313 ******************************************************************************/ | |
314 | |
315 /* | |
316 ** Print sketchy documentation for this utility program | |
317 */ | |
318 static void showHelp(void){ | |
319 printf("Usage: %s [options] ?FILE...?\n", g.zArgv0); | |
320 printf( | |
321 "Read SQL text from FILE... (or from standard input if FILE... is omitted)\n" | |
322 "and then evaluate each block of SQL contained therein.\n" | |
323 "Options:\n" | |
324 " --autovacuum Enable AUTOVACUUM mode\n" | |
325 " --database FILE Use database FILE instead of an in-memory database\n" | |
326 " --disable-lookaside Turn off lookaside memory\n" | |
327 " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n" | |
328 " --help Show this help text\n" | |
329 " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n" | |
330 " --oom Run each test multiple times in a simulated OOM loop\n" | |
331 " --pagesize N Set the page size to N\n" | |
332 " --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n" | |
333 " -q Reduced output\n" | |
334 " --quiet Reduced output\n" | |
335 " --scratch N SZ Configure scratch memory for N slots of SZ bytes each\n
" | |
336 " --unique-cases FILE Write all unique test cases to FILE\n" | |
337 " --utf16be Set text encoding to UTF-16BE\n" | |
338 " --utf16le Set text encoding to UTF-16LE\n" | |
339 " -v Increased output\n" | |
340 " --verbose Increased output\n" | |
341 ); | |
342 } | |
343 | |
344 /* | |
345 ** Return the value of a hexadecimal digit. Return -1 if the input | |
346 ** is not a hex digit. | |
347 */ | |
348 static int hexDigitValue(char c){ | |
349 if( c>='0' && c<='9' ) return c - '0'; | |
350 if( c>='a' && c<='f' ) return c - 'a' + 10; | |
351 if( c>='A' && c<='F' ) return c - 'A' + 10; | |
352 return -1; | |
353 } | |
354 | |
355 /* | |
356 ** Interpret zArg as an integer value, possibly with suffixes. | |
357 */ | |
358 static int integerValue(const char *zArg){ | |
359 sqlite3_int64 v = 0; | |
360 static const struct { char *zSuffix; int iMult; } aMult[] = { | |
361 { "KiB", 1024 }, | |
362 { "MiB", 1024*1024 }, | |
363 { "GiB", 1024*1024*1024 }, | |
364 { "KB", 1000 }, | |
365 { "MB", 1000000 }, | |
366 { "GB", 1000000000 }, | |
367 { "K", 1000 }, | |
368 { "M", 1000000 }, | |
369 { "G", 1000000000 }, | |
370 }; | |
371 int i; | |
372 int isNeg = 0; | |
373 if( zArg[0]=='-' ){ | |
374 isNeg = 1; | |
375 zArg++; | |
376 }else if( zArg[0]=='+' ){ | |
377 zArg++; | |
378 } | |
379 if( zArg[0]=='0' && zArg[1]=='x' ){ | |
380 int x; | |
381 zArg += 2; | |
382 while( (x = hexDigitValue(zArg[0]))>=0 ){ | |
383 v = (v<<4) + x; | |
384 zArg++; | |
385 } | |
386 }else{ | |
387 while( ISDIGIT(zArg[0]) ){ | |
388 v = v*10 + zArg[0] - '0'; | |
389 zArg++; | |
390 } | |
391 } | |
392 for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){ | |
393 if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){ | |
394 v *= aMult[i].iMult; | |
395 break; | |
396 } | |
397 } | |
398 if( v>0x7fffffff ) abendError("parameter too large - max 2147483648"); | |
399 return (int)(isNeg? -v : v); | |
400 } | |
401 | |
402 /* Return the current wall-clock time */ | |
403 static sqlite3_int64 timeOfDay(void){ | |
404 static sqlite3_vfs *clockVfs = 0; | |
405 sqlite3_int64 t; | |
406 if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); | |
407 if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){ | |
408 clockVfs->xCurrentTimeInt64(clockVfs, &t); | |
409 }else{ | |
410 double r; | |
411 clockVfs->xCurrentTime(clockVfs, &r); | |
412 t = (sqlite3_int64)(r*86400000.0); | |
413 } | |
414 return t; | |
415 } | |
416 | |
417 int main(int argc, char **argv){ | |
418 char *zIn = 0; /* Input text */ | |
419 int nAlloc = 0; /* Number of bytes allocated for zIn[] */ | |
420 int nIn = 0; /* Number of bytes of zIn[] used */ | |
421 size_t got; /* Bytes read from input */ | |
422 int rc = SQLITE_OK; /* Result codes from API functions */ | |
423 int i; /* Loop counter */ | |
424 int iNext; /* Next block of SQL */ | |
425 sqlite3 *db; /* Open database */ | |
426 char *zErrMsg = 0; /* Error message returned from sqlite3_exec() */ | |
427 const char *zEncoding = 0; /* --utf16be or --utf16le */ | |
428 int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ | |
429 int nLook = 0, szLook = 0; /* --lookaside configuration */ | |
430 int nPCache = 0, szPCache = 0;/* --pcache configuration */ | |
431 int nScratch = 0, szScratch=0;/* --scratch configuration */ | |
432 int pageSize = 0; /* Desired page size. 0 means default */ | |
433 void *pHeap = 0; /* Allocated heap space */ | |
434 void *pLook = 0; /* Allocated lookaside space */ | |
435 void *pPCache = 0; /* Allocated storage for pcache */ | |
436 void *pScratch = 0; /* Allocated storage for scratch */ | |
437 int doAutovac = 0; /* True for --autovacuum */ | |
438 char *zSql; /* SQL to run */ | |
439 char *zToFree = 0; /* Call sqlite3_free() on this afte running zSql
*/ | |
440 int verboseFlag = 0; /* --verbose or -v flag */ | |
441 int quietFlag = 0; /* --quiet or -q flag */ | |
442 int nTest = 0; /* Number of test cases run */ | |
443 int multiTest = 0; /* True if there will be multiple test cases */ | |
444 int lastPct = -1; /* Previous percentage done output */ | |
445 sqlite3 *dataDb = 0; /* Database holding compacted input data */ | |
446 sqlite3_stmt *pStmt = 0; /* Statement to insert testcase into dataDb */ | |
447 const char *zDataOut = 0; /* Write compacted data to this output file */ | |
448 int nHeader = 0; /* Bytes of header comment text on input file */ | |
449 int oomFlag = 0; /* --oom */ | |
450 int oomCnt = 0; /* Counter for the OOM loop */ | |
451 char zErrBuf[200]; /* Space for the error message */ | |
452 const char *zFailCode; /* Value of the TEST_FAILURE environment var */ | |
453 const char *zPrompt; /* Initial prompt when large-file fuzzing */ | |
454 int nInFile = 0; /* Number of input files to read */ | |
455 char **azInFile = 0; /* Array of input file names */ | |
456 int jj; /* Loop counter for azInFile[] */ | |
457 sqlite3_int64 iBegin; /* Start time for the whole program */ | |
458 sqlite3_int64 iStart, iEnd; /* Start and end-times for a test case */ | |
459 const char *zDbName = 0; /* Name of an on-disk database file to open */ | |
460 | |
461 iBegin = timeOfDay(); | |
462 sqlite3_shutdown(); | |
463 zFailCode = getenv("TEST_FAILURE"); | |
464 g.zArgv0 = argv[0]; | |
465 zPrompt = "<stdin>"; | |
466 for(i=1; i<argc; i++){ | |
467 const char *z = argv[i]; | |
468 if( z[0]=='-' ){ | |
469 z++; | |
470 if( z[0]=='-' ) z++; | |
471 if( strcmp(z,"autovacuum")==0 ){ | |
472 doAutovac = 1; | |
473 }else | |
474 if( strcmp(z,"database")==0 ){ | |
475 if( i>=argc-1 ) abendError("missing argument on %s\n", argv[i]); | |
476 zDbName = argv[i+1]; | |
477 i += 1; | |
478 }else | |
479 if( strcmp(z,"disable-lookaside")==0 ){ | |
480 nLook = 1; | |
481 szLook = 0; | |
482 }else | |
483 if( strcmp(z, "f")==0 && i+1<argc ){ | |
484 i++; | |
485 goto addNewInFile; | |
486 }else | |
487 if( strcmp(z,"heap")==0 ){ | |
488 if( i>=argc-2 ) abendError("missing arguments on %s\n", argv[i]); | |
489 nHeap = integerValue(argv[i+1]); | |
490 mnHeap = integerValue(argv[i+2]); | |
491 i += 2; | |
492 }else | |
493 if( strcmp(z,"help")==0 ){ | |
494 showHelp(); | |
495 return 0; | |
496 }else | |
497 if( strcmp(z,"lookaside")==0 ){ | |
498 if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); | |
499 nLook = integerValue(argv[i+1]); | |
500 szLook = integerValue(argv[i+2]); | |
501 i += 2; | |
502 }else | |
503 if( strcmp(z,"oom")==0 ){ | |
504 oomFlag = 1; | |
505 }else | |
506 if( strcmp(z,"pagesize")==0 ){ | |
507 if( i>=argc-1 ) abendError("missing argument on %s", argv[i]); | |
508 pageSize = integerValue(argv[++i]); | |
509 }else | |
510 if( strcmp(z,"pcache")==0 ){ | |
511 if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); | |
512 nPCache = integerValue(argv[i+1]); | |
513 szPCache = integerValue(argv[i+2]); | |
514 i += 2; | |
515 }else | |
516 if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){ | |
517 quietFlag = 1; | |
518 verboseFlag = 0; | |
519 }else | |
520 if( strcmp(z,"scratch")==0 ){ | |
521 if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); | |
522 nScratch = integerValue(argv[i+1]); | |
523 szScratch = integerValue(argv[i+2]); | |
524 i += 2; | |
525 }else | |
526 if( strcmp(z, "unique-cases")==0 ){ | |
527 if( i>=argc-1 ) abendError("missing arguments on %s", argv[i]); | |
528 if( zDataOut ) abendError("only one --minimize allowed"); | |
529 zDataOut = argv[++i]; | |
530 }else | |
531 if( strcmp(z,"utf16le")==0 ){ | |
532 zEncoding = "utf16le"; | |
533 }else | |
534 if( strcmp(z,"utf16be")==0 ){ | |
535 zEncoding = "utf16be"; | |
536 }else | |
537 if( strcmp(z,"verbose")==0 || strcmp(z,"v")==0 ){ | |
538 quietFlag = 0; | |
539 verboseFlag = 1; | |
540 }else | |
541 { | |
542 abendError("unknown option: %s", argv[i]); | |
543 } | |
544 }else{ | |
545 addNewInFile: | |
546 nInFile++; | |
547 azInFile = realloc(azInFile, sizeof(azInFile[0])*nInFile); | |
548 if( azInFile==0 ) abendError("out of memory"); | |
549 azInFile[nInFile-1] = argv[i]; | |
550 } | |
551 } | |
552 | |
553 /* Do global SQLite initialization */ | |
554 sqlite3_config(SQLITE_CONFIG_LOG, verboseFlag ? shellLog : shellLogNoop, 0); | |
555 if( nHeap>0 ){ | |
556 pHeap = malloc( nHeap ); | |
557 if( pHeap==0 ) fatalError("cannot allocate %d-byte heap\n", nHeap); | |
558 rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap); | |
559 if( rc ) abendError("heap configuration failed: %d\n", rc); | |
560 } | |
561 if( oomFlag ){ | |
562 sqlite3_config(SQLITE_CONFIG_GETMALLOC, &g.sOrigMem); | |
563 g.sOomMem = g.sOrigMem; | |
564 g.sOomMem.xMalloc = oomMalloc; | |
565 g.sOomMem.xRealloc = oomRealloc; | |
566 sqlite3_config(SQLITE_CONFIG_MALLOC, &g.sOomMem); | |
567 } | |
568 if( nLook>0 ){ | |
569 sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0); | |
570 if( szLook>0 ){ | |
571 pLook = malloc( nLook*szLook ); | |
572 if( pLook==0 ) fatalError("out of memory"); | |
573 } | |
574 } | |
575 if( nScratch>0 && szScratch>0 ){ | |
576 pScratch = malloc( nScratch*(sqlite3_int64)szScratch ); | |
577 if( pScratch==0 ) fatalError("cannot allocate %lld-byte scratch", | |
578 nScratch*(sqlite3_int64)szScratch); | |
579 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, pScratch, szScratch, nScratch); | |
580 if( rc ) abendError("scratch configuration failed: %d\n", rc); | |
581 } | |
582 if( nPCache>0 && szPCache>0 ){ | |
583 pPCache = malloc( nPCache*(sqlite3_int64)szPCache ); | |
584 if( pPCache==0 ) fatalError("cannot allocate %lld-byte pcache", | |
585 nPCache*(sqlite3_int64)szPCache); | |
586 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache); | |
587 if( rc ) abendError("pcache configuration failed: %d", rc); | |
588 } | |
589 | |
590 /* If the --unique-cases option was supplied, open the database that will | |
591 ** be used to gather unique test cases. | |
592 */ | |
593 if( zDataOut ){ | |
594 rc = sqlite3_open(":memory:", &dataDb); | |
595 if( rc ) abendError("cannot open :memory: database"); | |
596 rc = sqlite3_exec(dataDb, | |
597 "CREATE TABLE testcase(sql BLOB PRIMARY KEY, tm) WITHOUT ROWID;",0,0,0
); | |
598 if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); | |
599 rc = sqlite3_prepare_v2(dataDb, | |
600 "INSERT OR IGNORE INTO testcase(sql,tm)VALUES(?1,?2)", | |
601 -1, &pStmt, 0); | |
602 if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); | |
603 } | |
604 | |
605 /* Initialize the input buffer used to hold SQL text */ | |
606 if( nInFile==0 ) nInFile = 1; | |
607 nAlloc = 1000; | |
608 zIn = malloc(nAlloc); | |
609 if( zIn==0 ) fatalError("out of memory"); | |
610 | |
611 /* Loop over all input files */ | |
612 for(jj=0; jj<nInFile; jj++){ | |
613 | |
614 /* Read the complete content of the next input file into zIn[] */ | |
615 FILE *in; | |
616 if( azInFile ){ | |
617 int j, k; | |
618 in = fopen(azInFile[jj],"rb"); | |
619 if( in==0 ){ | |
620 abendError("cannot open %s for reading", azInFile[jj]); | |
621 } | |
622 zPrompt = azInFile[jj]; | |
623 for(j=k=0; zPrompt[j]; j++) if( zPrompt[j]=='/' ) k = j+1; | |
624 zPrompt += k; | |
625 }else{ | |
626 in = stdin; | |
627 zPrompt = "<stdin>"; | |
628 } | |
629 while( !feof(in) ){ | |
630 got = fread(zIn+nIn, 1, nAlloc-nIn-1, in); | |
631 nIn += (int)got; | |
632 zIn[nIn] = 0; | |
633 if( got==0 ) break; | |
634 if( nAlloc - nIn - 1 < 100 ){ | |
635 nAlloc += nAlloc+1000; | |
636 zIn = realloc(zIn, nAlloc); | |
637 if( zIn==0 ) fatalError("out of memory"); | |
638 } | |
639 } | |
640 if( in!=stdin ) fclose(in); | |
641 lastPct = -1; | |
642 | |
643 /* Skip initial lines of the input file that begin with "#" */ | |
644 for(i=0; i<nIn; i=iNext+1){ | |
645 if( zIn[i]!='#' ) break; | |
646 for(iNext=i+1; iNext<nIn && zIn[iNext]!='\n'; iNext++){} | |
647 } | |
648 nHeader = i; | |
649 | |
650 /* Process all test cases contained within the input file. | |
651 */ | |
652 for(; i<nIn; i=iNext, nTest++, g.zTestName[0]=0){ | |
653 char cSaved; | |
654 if( strncmp(&zIn[i], "/****<",6)==0 ){ | |
655 char *z = strstr(&zIn[i], ">****/"); | |
656 if( z ){ | |
657 z += 6; | |
658 sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "%.*s", | |
659 (int)(z-&zIn[i]) - 12, &zIn[i+6]); | |
660 if( verboseFlag ){ | |
661 printf("%.*s\n", (int)(z-&zIn[i]), &zIn[i]); | |
662 fflush(stdout); | |
663 } | |
664 i += (int)(z-&zIn[i]); | |
665 multiTest = 1; | |
666 } | |
667 } | |
668 for(iNext=i; iNext<nIn && strncmp(&zIn[iNext],"/****<",6)!=0; iNext++){} | |
669 cSaved = zIn[iNext]; | |
670 zIn[iNext] = 0; | |
671 | |
672 | |
673 /* Print out the SQL of the next test case is --verbose is enabled | |
674 */ | |
675 zSql = &zIn[i]; | |
676 if( verboseFlag ){ | |
677 printf("INPUT (offset: %d, size: %d): [%s]\n", | |
678 i, (int)strlen(&zIn[i]), &zIn[i]); | |
679 }else if( multiTest && !quietFlag ){ | |
680 if( oomFlag ){ | |
681 printf("%s\n", g.zTestName); | |
682 }else{ | |
683 int pct = (10*iNext)/nIn; | |
684 if( pct!=lastPct ){ | |
685 if( lastPct<0 ) printf("%s:", zPrompt); | |
686 printf(" %d%%", pct*10); | |
687 lastPct = pct; | |
688 } | |
689 } | |
690 }else if( nInFile>1 ){ | |
691 printf("%s\n", zPrompt); | |
692 } | |
693 fflush(stdout); | |
694 | |
695 /* Run the next test case. Run it multiple times in --oom mode | |
696 */ | |
697 if( oomFlag ){ | |
698 oomCnt = g.iOomCntdown = 1; | |
699 g.nOomFault = 0; | |
700 g.bOomOnce = 1; | |
701 if( verboseFlag ){ | |
702 printf("Once.%d\n", oomCnt); | |
703 fflush(stdout); | |
704 } | |
705 }else{ | |
706 oomCnt = 0; | |
707 } | |
708 do{ | |
709 if( zDbName ){ | |
710 rc = sqlite3_open_v2(zDbName, &db, SQLITE_OPEN_READWRITE, 0); | |
711 if( rc!=SQLITE_OK ){ | |
712 abendError("Cannot open database file %s", zDbName); | |
713 } | |
714 }else{ | |
715 rc = sqlite3_open_v2( | |
716 "main.db", &db, | |
717 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY, | |
718 0); | |
719 if( rc!=SQLITE_OK ){ | |
720 abendError("Unable to open the in-memory database"); | |
721 } | |
722 } | |
723 if( pLook ){ | |
724 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE,pLook,szLook,nLoo
k); | |
725 if( rc!=SQLITE_OK ) abendError("lookaside configuration filed: %d", rc
); | |
726 } | |
727 #ifndef SQLITE_OMIT_TRACE | |
728 sqlite3_trace(db, verboseFlag ? traceCallback : traceNoop, 0); | |
729 #endif | |
730 sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0
); | |
731 sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0
); | |
732 sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 1000000); | |
733 if( zEncoding ) sqlexec(db, "PRAGMA encoding=%s", zEncoding); | |
734 if( pageSize ) sqlexec(db, "PRAGMA pagesize=%d", pageSize); | |
735 if( doAutovac ) sqlexec(db, "PRAGMA auto_vacuum=FULL"); | |
736 iStart = timeOfDay(); | |
737 g.bOomEnable = 1; | |
738 if( verboseFlag ){ | |
739 zErrMsg = 0; | |
740 rc = sqlite3_exec(db, zSql, execCallback, 0, &zErrMsg); | |
741 if( zErrMsg ){ | |
742 sqlite3_snprintf(sizeof(zErrBuf),zErrBuf,"%z", zErrMsg); | |
743 zErrMsg = 0; | |
744 } | |
745 }else { | |
746 rc = sqlite3_exec(db, zSql, execNoop, 0, 0); | |
747 } | |
748 g.bOomEnable = 0; | |
749 iEnd = timeOfDay(); | |
750 rc = sqlite3_close(db); | |
751 if( rc ){ | |
752 abendError("sqlite3_close() failed with rc=%d", rc); | |
753 } | |
754 if( !zDataOut && sqlite3_memory_used()>0 ){ | |
755 abendError("memory in use after close: %lld bytes",sqlite3_memory_used
()); | |
756 } | |
757 if( oomFlag ){ | |
758 /* Limit the number of iterations of the OOM loop to OOM_MAX. If the | |
759 ** first pass (single failure) exceeds 2/3rds of OOM_MAX this skip the | |
760 ** second pass (continuous failure after first) completely. */ | |
761 if( g.nOomFault==0 || oomCnt>OOM_MAX ){ | |
762 if( g.bOomOnce && oomCnt<=(OOM_MAX*2/3) ){ | |
763 oomCnt = g.iOomCntdown = 1; | |
764 g.bOomOnce = 0; | |
765 }else{ | |
766 oomCnt = 0; | |
767 } | |
768 }else{ | |
769 g.iOomCntdown = ++oomCnt; | |
770 g.nOomFault = 0; | |
771 } | |
772 if( oomCnt ){ | |
773 if( verboseFlag ){ | |
774 printf("%s.%d\n", g.bOomOnce ? "Once" : "Multi", oomCnt); | |
775 fflush(stdout); | |
776 } | |
777 nTest++; | |
778 } | |
779 } | |
780 }while( oomCnt>0 ); | |
781 | |
782 /* Store unique test cases in the in the dataDb database if the | |
783 ** --unique-cases flag is present | |
784 */ | |
785 if( zDataOut ){ | |
786 sqlite3_bind_blob(pStmt, 1, &zIn[i], iNext-i, SQLITE_STATIC); | |
787 sqlite3_bind_int64(pStmt, 2, iEnd - iStart); | |
788 rc = sqlite3_step(pStmt); | |
789 if( rc!=SQLITE_DONE ) abendError("%s", sqlite3_errmsg(dataDb)); | |
790 sqlite3_reset(pStmt); | |
791 } | |
792 | |
793 /* Free the SQL from the current test case | |
794 */ | |
795 if( zToFree ){ | |
796 sqlite3_free(zToFree); | |
797 zToFree = 0; | |
798 } | |
799 zIn[iNext] = cSaved; | |
800 | |
801 /* Show test-case results in --verbose mode | |
802 */ | |
803 if( verboseFlag ){ | |
804 printf("RESULT-CODE: %d\n", rc); | |
805 if( zErrMsg ){ | |
806 printf("ERROR-MSG: [%s]\n", zErrBuf); | |
807 } | |
808 fflush(stdout); | |
809 } | |
810 | |
811 /* Simulate an error if the TEST_FAILURE environment variable is "5". | |
812 ** This is used to verify that automated test script really do spot | |
813 ** errors that occur in this test program. | |
814 */ | |
815 if( zFailCode ){ | |
816 if( zFailCode[0]=='5' && zFailCode[1]==0 ){ | |
817 abendError("simulated failure"); | |
818 }else if( zFailCode[0]!=0 ){ | |
819 /* If TEST_FAILURE is something other than 5, just exit the test | |
820 ** early */ | |
821 printf("\nExit early due to TEST_FAILURE being set"); | |
822 break; | |
823 } | |
824 } | |
825 } | |
826 if( !verboseFlag && multiTest && !quietFlag && !oomFlag ) printf("\n"); | |
827 } | |
828 | |
829 /* Report total number of tests run | |
830 */ | |
831 if( nTest>1 && !quietFlag ){ | |
832 sqlite3_int64 iElapse = timeOfDay() - iBegin; | |
833 printf("%s: 0 errors out of %d tests in %d.%03d seconds\nSQLite %s %s\n", | |
834 g.zArgv0, nTest, (int)(iElapse/1000), (int)(iElapse%1000), | |
835 sqlite3_libversion(), sqlite3_sourceid()); | |
836 } | |
837 | |
838 /* Write the unique test cases if the --unique-cases flag was used | |
839 */ | |
840 if( zDataOut ){ | |
841 int n = 0; | |
842 FILE *out = fopen(zDataOut, "wb"); | |
843 if( out==0 ) abendError("cannot open %s for writing", zDataOut); | |
844 if( nHeader>0 ) fwrite(zIn, nHeader, 1, out); | |
845 sqlite3_finalize(pStmt); | |
846 rc = sqlite3_prepare_v2(dataDb, "SELECT sql, tm FROM testcase ORDER BY tm, s
ql", | |
847 -1, &pStmt, 0); | |
848 if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); | |
849 while( sqlite3_step(pStmt)==SQLITE_ROW ){ | |
850 fprintf(out,"/****<%d:%dms>****/", ++n, sqlite3_column_int(pStmt,1)); | |
851 fwrite(sqlite3_column_blob(pStmt,0),sqlite3_column_bytes(pStmt,0),1,out); | |
852 } | |
853 fclose(out); | |
854 sqlite3_finalize(pStmt); | |
855 sqlite3_close(dataDb); | |
856 } | |
857 | |
858 /* Clean up and exit. | |
859 */ | |
860 free(azInFile); | |
861 free(zIn); | |
862 free(pHeap); | |
863 free(pLook); | |
864 free(pScratch); | |
865 free(pPCache); | |
866 return 0; | |
867 } | |
OLD | NEW |