xref: /sqlite-3.40.0/test/dbfuzz2.c (revision 7ac2ee0a)
1 /*
2 ** 2018-10-26
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 program is designed for fuzz-testing SQLite database files using
14 ** the -fsanitize=fuzzer option of clang.
15 **
16 ** The -fsanitize=fuzzer option causes a main() to be inserted automatically.
17 ** That main() invokes LLVMFuzzerTestOneInput(D,S) to be invoked repeatedly.
18 ** Each D is a fuzzed database file.  The code in this file runs various
19 ** SQL statements against that database, trying to provoke a failure.
20 **
21 ** For best results the seed database files should have these tables:
22 **
23 **   Table "t1" with columns "a" and "b"
24 **   Tables "t2" and "t3 with the same number of compatible columns
25 **       "t3" should have a column names "x"
26 **   Table "t4" with a column "x" that is compatible with t3.x.
27 **
28 ** Any of these tables can be virtual tables, for example FTS or RTree tables.
29 **
30 ** To run this test:
31 **
32 **     mkdir dir
33 **     cp dbfuzz2-seed*.db dir
34 **     clang-6.0 -I. -g -O1 -fsanitize=fuzzer \
35 **       -DTHREADSAFE=0 -DSQLITE_ENABLE_DESERIALIZE \
36 **       -DSQLITE_ENABLE_DBSTAT_VTAB dbfuzz2.c sqlite3.c -ldl
37 **     ./a.out dir
38 */
39 #include <assert.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #include <ctype.h>
45 #include <stdint.h>
46 #ifndef _WIN32
47 #include <sys/time.h>
48 #include <sys/resource.h>
49 #endif
50 #include "sqlite3.h"
51 
52 /*
53 ** This is the is the SQL that is run against the database.
54 */
55 static const char *azSql[] = {
56   "PRAGMA integrity_check;",
57   "SELECT * FROM sqlite_master;",
58   "SELECT sum(length(name)) FROM dbstat;",
59   "UPDATE t1 SET b=a, a=b WHERE a<b;",
60   "ALTER TABLE t1 RENAME TO alkjalkjdfiiiwuer987lkjwer82mx97sf98788s9789s;",
61   "INSERT INTO t3 SELECT * FROM t2;",
62   "DELETE FROM t3 WHERE x IN (SELECT x FROM t4);",
63   "REINDEX;",
64   "DROP TABLE t3;",
65   "VACUUM;",
66 };
67 
68 /* Output verbosity level.  0 means complete silence */
69 int eVerbosity = 0;
70 
71 /* True to activate PRAGMA vdbe_debug=on */
72 static int bVdbeDebug = 0;
73 
74 /* Maximum size of the in-memory database file */
75 static sqlite3_int64 szMax = 104857600;
76 
77 /***** Copy/paste from ext/misc/memtrace.c ***************************/
78 /* The original memory allocation routines */
79 static sqlite3_mem_methods memtraceBase;
80 static FILE *memtraceOut;
81 
82 /* Methods that trace memory allocations */
83 static void *memtraceMalloc(int n){
84   if( memtraceOut ){
85     fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n",
86             memtraceBase.xRoundup(n));
87   }
88   return memtraceBase.xMalloc(n);
89 }
90 static void memtraceFree(void *p){
91   if( p==0 ) return;
92   if( memtraceOut ){
93     fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p));
94   }
95   memtraceBase.xFree(p);
96 }
97 static void *memtraceRealloc(void *p, int n){
98   if( p==0 ) return memtraceMalloc(n);
99   if( n==0 ){
100     memtraceFree(p);
101     return 0;
102   }
103   if( memtraceOut ){
104     fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n",
105             memtraceBase.xSize(p), memtraceBase.xRoundup(n));
106   }
107   return memtraceBase.xRealloc(p, n);
108 }
109 static int memtraceSize(void *p){
110   return memtraceBase.xSize(p);
111 }
112 static int memtraceRoundup(int n){
113   return memtraceBase.xRoundup(n);
114 }
115 static int memtraceInit(void *p){
116   return memtraceBase.xInit(p);
117 }
118 static void memtraceShutdown(void *p){
119   memtraceBase.xShutdown(p);
120 }
121 
122 /* The substitute memory allocator */
123 static sqlite3_mem_methods ersaztMethods = {
124   memtraceMalloc,
125   memtraceFree,
126   memtraceRealloc,
127   memtraceSize,
128   memtraceRoundup,
129   memtraceInit,
130   memtraceShutdown
131 };
132 
133 /* Begin tracing memory allocations to out. */
134 int sqlite3MemTraceActivate(FILE *out){
135   int rc = SQLITE_OK;
136   if( memtraceBase.xMalloc==0 ){
137     rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase);
138     if( rc==SQLITE_OK ){
139       rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods);
140     }
141   }
142   memtraceOut = out;
143   return rc;
144 }
145 
146 /* Deactivate memory tracing */
147 int sqlite3MemTraceDeactivate(void){
148   int rc = SQLITE_OK;
149   if( memtraceBase.xMalloc!=0 ){
150     rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase);
151     if( rc==SQLITE_OK ){
152       memset(&memtraceBase, 0, sizeof(memtraceBase));
153     }
154   }
155   memtraceOut = 0;
156   return rc;
157 }
158 /***** End copy/paste from ext/misc/memtrace.c ***************************/
159 
160 /* libFuzzer invokes this routine with fuzzed database files (in aData).
161 ** This routine run SQLite against the malformed database to see if it
162 ** can provoke a failure or malfunction.
163 */
164 int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){
165   unsigned char *a;
166   sqlite3 *db;
167   int rc;
168   int i;
169   sqlite3_int64 x;
170   char *zErr = 0;
171 
172   if( eVerbosity>=1 ){
173     printf("************** nByte=%d ***************\n", (int)nByte);
174     fflush(stdout);
175   }
176   if( sqlite3_initialize() ) return 0;
177   rc = sqlite3_open(0, &db);
178   if( rc ) return 1;
179   a = sqlite3_malloc64(nByte+1);
180   if( a==0 ) return 1;
181   memcpy(a, aData, nByte);
182   sqlite3_deserialize(db, "main", a, nByte, nByte,
183         SQLITE_DESERIALIZE_RESIZEABLE |
184         SQLITE_DESERIALIZE_FREEONCLOSE);
185   x = szMax;
186 #ifdef SQLITE_FCNTL_SIZE_LIMIT
187   sqlite3_file_control(db, "main", SQLITE_FCNTL_SIZE_LIMIT, &x);
188 #endif
189   if( bVdbeDebug ){
190     sqlite3_exec(db, "PRAGMA vdbe_debug=ON", 0, 0, 0);
191   }
192   for(i=0; i<sizeof(azSql)/sizeof(azSql[0]); i++){
193     if( eVerbosity>=1 ){
194       printf("%s\n", azSql[i]);
195       fflush(stdout);
196     }
197     zErr = 0;
198     rc = sqlite3_exec(db, azSql[i], 0, 0, &zErr);
199     if( rc && eVerbosity>=1 ){
200       printf("-- rc=%d zErr=%s\n", rc, zErr);
201     }
202     sqlite3_free(zErr);
203   }
204   rc = sqlite3_close(db);
205   if( rc!=SQLITE_OK ){
206     fprintf(stdout, "sqlite3_close() returns %d\n", rc);
207   }
208   if( sqlite3_memory_used()!=0 ){
209     int nAlloc = 0;
210     int nNotUsed = 0;
211     sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &nAlloc, &nNotUsed, 0);
212     fprintf(stderr,"Memory leak: %lld bytes in %d allocations\n",
213             sqlite3_memory_used(), nAlloc);
214     exit(1);
215   }
216   return 0;
217 }
218 
219 /*
220 ** Return the number of "v" characters in a string.  Return 0 if there
221 ** are any characters in the string other than "v".
222 */
223 static int numberOfVChar(const char *z){
224   int N = 0;
225   while( z[0] && z[0]=='v' ){
226     z++;
227     N++;
228   }
229   return z[0]==0 ? N : 0;
230 }
231 
232 /* libFuzzer invokes this routine once when the executable starts, to
233 ** process the command-line arguments.
234 */
235 int LLVMFuzzerInitialize(int *pArgc, char ***pArgv){
236   int i, j, n;
237   int argc = *pArgc;
238   char **argv = *pArgv;
239   for(i=j=1; i<argc; i++){
240     char *z = argv[i];
241     if( z[0]=='-' ){
242       z++;
243       if( z[0]=='-' ) z++;
244       if( z[0]=='v' && (n = numberOfVChar(z))>0 ){
245         eVerbosity += n;
246         continue;
247       }
248       if( strcmp(z,"vdbe-debug")==0 ){
249         bVdbeDebug = 1;
250         continue;
251       }
252       if( strcmp(z,"memtrace")==0 ){
253         sqlite3MemTraceActivate(stdout);
254         continue;
255       }
256       if( strcmp(z,"mem")==0 ){
257         bVdbeDebug = 1;
258         continue;
259       }
260       if( strcmp(z,"max-db-size")==0 ){
261         if( i+1==argc ){
262           fprintf(stderr, "missing argument to %s\n", argv[i]);
263           exit(1);
264         }
265         szMax = strtol(argv[++i], 0, 0);
266         continue;
267       }
268 #ifndef _WIN32
269       if( strcmp(z,"max-stack")==0
270        || strcmp(z,"max-data")==0
271        || strcmp(z,"max-as")==0
272       ){
273         struct rlimit x,y;
274         int resource = RLIMIT_STACK;
275         char *zType = "RLIMIT_STACK";
276         if( i+1==argc ){
277           fprintf(stderr, "missing argument to %s\n", argv[i]);
278           exit(1);
279         }
280         if( z[4]=='d' ){
281           resource = RLIMIT_DATA;
282           zType = "RLIMIT_DATA";
283         }
284         if( z[4]=='a' ){
285           resource = RLIMIT_AS;
286           zType = "RLIMIT_AS";
287         }
288         memset(&x,0,sizeof(x));
289         getrlimit(resource, &x);
290         y.rlim_cur = atoi(argv[++i]);
291         y.rlim_max = x.rlim_cur;
292         setrlimit(resource, &y);
293         memset(&y,0,sizeof(y));
294         getrlimit(resource, &y);
295         printf("%s changed from %d to %d\n",
296                zType, (int)x.rlim_cur, (int)y.rlim_cur);
297         continue;
298       }
299 #endif /* _WIN32 */
300     }
301     argv[j++] = argv[i];
302   }
303   argv[j] = 0;
304   *pArgc = j;
305   return 0;
306 }
307 
308 #ifdef STANDALONE
309 /*
310 ** Read an entire file into memory.  Space to hold the file comes
311 ** from malloc().
312 */
313 static unsigned char *readFile(const char *zName, int *pnByte){
314   FILE *in = fopen(zName, "rb");
315   long nIn;
316   size_t nRead;
317   unsigned char *pBuf;
318   if( in==0 ) return 0;
319   fseek(in, 0, SEEK_END);
320   nIn = ftell(in);
321   rewind(in);
322   pBuf = malloc( nIn+1 );
323   if( pBuf==0 ){ fclose(in); return 0; }
324   nRead = fread(pBuf, nIn, 1, in);
325   fclose(in);
326   if( nRead!=1 ){
327     free(pBuf);
328     return 0;
329   }
330   pBuf[nIn] = 0;
331   if( pnByte ) *pnByte = nIn;
332   return pBuf;
333 }
334 #endif /* STANDALONE */
335 
336 #ifdef STANDALONE
337 int main(int argc, char **argv){
338   int i;
339   LLVMFuzzerInitialize(&argc, &argv);
340   for(i=1; i<argc; i++){
341     unsigned char *pIn;
342     int nIn;
343     pIn = readFile(argv[i], &nIn);
344     if( pIn ){
345       LLVMFuzzerTestOneInput((const uint8_t*)pIn, (size_t)nIn);
346       free(pIn);
347     }
348   }
349   if( eVerbosity>0 ){
350     struct rusage x;
351     printf("SQLite %s\n", sqlite3_sourceid());
352     memset(&x, 0, sizeof(x));
353     if( getrusage(RUSAGE_SELF, &x)==0 ){
354       printf("Maximum RSS = %ld KB\n", x.ru_maxrss);
355     }
356   }
357   return 0;
358 }
359 #endif /*STANDALONE*/
360