xref: /sqlite-3.40.0/src/test_malloc.c (revision 9a23d26c)
1 /*
2 ** 2007 August 15
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 file contains code used to implement test interfaces to the
14 ** memory allocation subsystem.
15 */
16 #include "sqliteInt.h"
17 #if defined(INCLUDE_SQLITE_TCL_H)
18 #  include "sqlite_tcl.h"
19 #else
20 #  include "tcl.h"
21 #endif
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
25 
26 /*
27 ** This structure is used to encapsulate the global state variables used
28 ** by malloc() fault simulation.
29 */
30 static struct MemFault {
31   int iCountdown;         /* Number of pending successes before a failure */
32   int nRepeat;            /* Number of times to repeat the failure */
33   int nBenign;            /* Number of benign failures seen since last config */
34   int nFail;              /* Number of failures seen since last config */
35   int nOkBefore;          /* Successful allocations prior to the first fault */
36   int nOkAfter;           /* Successful allocations after a fault */
37   u8 enable;              /* True if enabled */
38   int isInstalled;        /* True if the fault simulation layer is installed */
39   int isBenignMode;       /* True if malloc failures are considered benign */
40   sqlite3_mem_methods m;  /* 'Real' malloc implementation */
41 } memfault;
42 
43 /*
44 ** This routine exists as a place to set a breakpoint that will
45 ** fire on any simulated malloc() failure.
46 */
sqlite3Fault(void)47 static void sqlite3Fault(void){
48   static int cnt = 0;
49   cnt++;
50 }
51 
52 /*
53 ** This routine exists as a place to set a breakpoint that will
54 ** fire the first time any malloc() fails on a single test case.
55 ** The sqlite3Fault() routine above runs on every malloc() failure.
56 ** This routine only runs on the first such failure.
57 */
sqlite3FirstFault(void)58 static void sqlite3FirstFault(void){
59   static int cnt2 = 0;
60   cnt2++;
61 }
62 
63 /*
64 ** Check to see if a fault should be simulated.  Return true to simulate
65 ** the fault.  Return false if the fault should not be simulated.
66 */
faultsimStep(void)67 static int faultsimStep(void){
68   if( likely(!memfault.enable) ){
69     memfault.nOkAfter++;
70     return 0;
71   }
72   if( memfault.iCountdown>0 ){
73     memfault.iCountdown--;
74     memfault.nOkBefore++;
75     return 0;
76   }
77   if( memfault.nFail==0 ) sqlite3FirstFault();
78   sqlite3Fault();
79   memfault.nFail++;
80   if( memfault.isBenignMode>0 ){
81     memfault.nBenign++;
82   }
83   memfault.nRepeat--;
84   if( memfault.nRepeat<=0 ){
85     memfault.enable = 0;
86   }
87   return 1;
88 }
89 
90 /*
91 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
92 ** logic.
93 */
faultsimMalloc(int n)94 static void *faultsimMalloc(int n){
95   void *p = 0;
96   if( !faultsimStep() ){
97     p = memfault.m.xMalloc(n);
98   }
99   return p;
100 }
101 
102 
103 /*
104 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
105 ** logic.
106 */
faultsimRealloc(void * pOld,int n)107 static void *faultsimRealloc(void *pOld, int n){
108   void *p = 0;
109   if( !faultsimStep() ){
110     p = memfault.m.xRealloc(pOld, n);
111   }
112   return p;
113 }
114 
115 /*
116 ** This routine configures the malloc failure simulation.  After
117 ** calling this routine, the next nDelay mallocs will succeed, followed
118 ** by a block of nRepeat failures, after which malloc() calls will begin
119 ** to succeed again.
120 */
faultsimConfig(int nDelay,int nRepeat)121 static void faultsimConfig(int nDelay, int nRepeat){
122   memfault.iCountdown = nDelay;
123   memfault.nRepeat = nRepeat;
124   memfault.nBenign = 0;
125   memfault.nFail = 0;
126   memfault.nOkBefore = 0;
127   memfault.nOkAfter = 0;
128   memfault.enable = nDelay>=0;
129 
130   /* Sometimes, when running multi-threaded tests, the isBenignMode
131   ** variable is not properly incremented/decremented so that it is
132   ** 0 when not inside a benign malloc block. This doesn't affect
133   ** the multi-threaded tests, as they do not use this system. But
134   ** it does affect OOM tests run later in the same process. So
135   ** zero the variable here, just to be sure.
136   */
137   memfault.isBenignMode = 0;
138 }
139 
140 /*
141 ** Return the number of faults (both hard and benign faults) that have
142 ** occurred since the injector was last configured.
143 */
faultsimFailures(void)144 static int faultsimFailures(void){
145   return memfault.nFail;
146 }
147 
148 /*
149 ** Return the number of benign faults that have occurred since the
150 ** injector was last configured.
151 */
faultsimBenignFailures(void)152 static int faultsimBenignFailures(void){
153   return memfault.nBenign;
154 }
155 
156 /*
157 ** Return the number of successes that will occur before the next failure.
158 ** If no failures are scheduled, return -1.
159 */
faultsimPending(void)160 static int faultsimPending(void){
161   if( memfault.enable ){
162     return memfault.iCountdown;
163   }else{
164     return -1;
165   }
166 }
167 
168 
faultsimBeginBenign(void)169 static void faultsimBeginBenign(void){
170   memfault.isBenignMode++;
171 }
faultsimEndBenign(void)172 static void faultsimEndBenign(void){
173   memfault.isBenignMode--;
174 }
175 
176 /*
177 ** Add or remove the fault-simulation layer using sqlite3_config(). If
178 ** the argument is non-zero, the
179 */
faultsimInstall(int install)180 static int faultsimInstall(int install){
181   int rc;
182 
183   install = (install ? 1 : 0);
184   assert(memfault.isInstalled==1 || memfault.isInstalled==0);
185 
186   if( install==memfault.isInstalled ){
187     return SQLITE_ERROR;
188   }
189 
190   if( install ){
191     rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
192     assert(memfault.m.xMalloc);
193     if( rc==SQLITE_OK ){
194       sqlite3_mem_methods m = memfault.m;
195       m.xMalloc = faultsimMalloc;
196       m.xRealloc = faultsimRealloc;
197       rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
198     }
199     sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
200         faultsimBeginBenign, faultsimEndBenign
201     );
202   }else{
203     sqlite3_mem_methods m2;
204     assert(memfault.m.xMalloc);
205 
206     /* One should be able to reset the default memory allocator by storing
207     ** a zeroed allocator then calling GETMALLOC. */
208     memset(&m2, 0, sizeof(m2));
209     sqlite3_config(SQLITE_CONFIG_MALLOC, &m2);
210     sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m2);
211     assert( memcmp(&m2, &memfault.m, sizeof(m2))==0 );
212 
213     rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
214     sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
215         (void*)0, (void*)0);
216   }
217 
218   if( rc==SQLITE_OK ){
219     memfault.isInstalled = 1;
220   }
221   return rc;
222 }
223 
224 #ifdef SQLITE_TEST
225 
226 /*
227 ** This function is implemented in main.c. Returns a pointer to a static
228 ** buffer containing the symbolic SQLite error code that corresponds to
229 ** the least-significant 8-bits of the integer passed as an argument.
230 ** For example:
231 **
232 **   sqlite3ErrName(1) -> "SQLITE_ERROR"
233 */
234 extern const char *sqlite3ErrName(int);
235 
236 /*
237 ** Transform pointers to text and back again
238 */
pointerToText(void * p,char * z)239 static void pointerToText(void *p, char *z){
240   static const char zHex[] = "0123456789abcdef";
241   int i, k;
242   unsigned int u;
243   sqlite3_uint64 n;
244   if( p==0 ){
245     strcpy(z, "0");
246     return;
247   }
248   if( sizeof(n)==sizeof(p) ){
249     memcpy(&n, &p, sizeof(p));
250   }else if( sizeof(u)==sizeof(p) ){
251     memcpy(&u, &p, sizeof(u));
252     n = u;
253   }else{
254     assert( 0 );
255   }
256   for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
257     z[k] = zHex[n&0xf];
258     n >>= 4;
259   }
260   z[sizeof(p)*2] = 0;
261 }
hexToInt(int h)262 static int hexToInt(int h){
263   if( h>='0' && h<='9' ){
264     return h - '0';
265   }else if( h>='a' && h<='f' ){
266     return h - 'a' + 10;
267   }else{
268     return -1;
269   }
270 }
textToPointer(const char * z,void ** pp)271 static int textToPointer(const char *z, void **pp){
272   sqlite3_uint64 n = 0;
273   int i;
274   unsigned int u;
275   for(i=0; i<sizeof(void*)*2 && z[0]; i++){
276     int v;
277     v = hexToInt(*z++);
278     if( v<0 ) return TCL_ERROR;
279     n = n*16 + v;
280   }
281   if( *z!=0 ) return TCL_ERROR;
282   if( sizeof(n)==sizeof(*pp) ){
283     memcpy(pp, &n, sizeof(n));
284   }else if( sizeof(u)==sizeof(*pp) ){
285     u = (unsigned int)n;
286     memcpy(pp, &u, sizeof(u));
287   }else{
288     assert( 0 );
289   }
290   return TCL_OK;
291 }
292 
293 /*
294 ** Usage:    sqlite3_malloc  NBYTES
295 **
296 ** Raw test interface for sqlite3_malloc().
297 */
test_malloc(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])298 static int SQLITE_TCLAPI test_malloc(
299   void * clientData,
300   Tcl_Interp *interp,
301   int objc,
302   Tcl_Obj *CONST objv[]
303 ){
304   int nByte;
305   void *p;
306   char zOut[100];
307   if( objc!=2 ){
308     Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
309     return TCL_ERROR;
310   }
311   if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
312   p = sqlite3_malloc((unsigned)nByte);
313   pointerToText(p, zOut);
314   Tcl_AppendResult(interp, zOut, NULL);
315   return TCL_OK;
316 }
317 
318 /*
319 ** Usage:    sqlite3_realloc  PRIOR  NBYTES
320 **
321 ** Raw test interface for sqlite3_realloc().
322 */
test_realloc(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])323 static int SQLITE_TCLAPI test_realloc(
324   void * clientData,
325   Tcl_Interp *interp,
326   int objc,
327   Tcl_Obj *CONST objv[]
328 ){
329   int nByte;
330   void *pPrior, *p;
331   char zOut[100];
332   if( objc!=3 ){
333     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
334     return TCL_ERROR;
335   }
336   if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
337   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
338     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
339     return TCL_ERROR;
340   }
341   p = sqlite3_realloc(pPrior, (unsigned)nByte);
342   pointerToText(p, zOut);
343   Tcl_AppendResult(interp, zOut, NULL);
344   return TCL_OK;
345 }
346 
347 /*
348 ** Usage:    sqlite3_free  PRIOR
349 **
350 ** Raw test interface for sqlite3_free().
351 */
test_free(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])352 static int SQLITE_TCLAPI test_free(
353   void * clientData,
354   Tcl_Interp *interp,
355   int objc,
356   Tcl_Obj *CONST objv[]
357 ){
358   void *pPrior;
359   if( objc!=2 ){
360     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
361     return TCL_ERROR;
362   }
363   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
364     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
365     return TCL_ERROR;
366   }
367   sqlite3_free(pPrior);
368   return TCL_OK;
369 }
370 
371 /*
372 ** These routines are in test_hexio.c
373 */
374 int sqlite3TestHexToBin(const char *, int, char *);
375 int sqlite3TestBinToHex(char*,int);
376 
377 /*
378 ** Usage:    memset  ADDRESS  SIZE  HEX
379 **
380 ** Set a chunk of memory (obtained from malloc, probably) to a
381 ** specified hex pattern.
382 */
test_memset(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])383 static int SQLITE_TCLAPI test_memset(
384   void * clientData,
385   Tcl_Interp *interp,
386   int objc,
387   Tcl_Obj *CONST objv[]
388 ){
389   void *p;
390   int size, n, i;
391   char *zHex;
392   char *zOut;
393   char zBin[100];
394 
395   if( objc!=4 ){
396     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
397     return TCL_ERROR;
398   }
399   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
400     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
401     return TCL_ERROR;
402   }
403   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
404     return TCL_ERROR;
405   }
406   if( size<=0 ){
407     Tcl_AppendResult(interp, "size must be positive", (char*)0);
408     return TCL_ERROR;
409   }
410   zHex = Tcl_GetStringFromObj(objv[3], &n);
411   if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
412   n = sqlite3TestHexToBin(zHex, n, zBin);
413   if( n==0 ){
414     Tcl_AppendResult(interp, "no data", (char*)0);
415     return TCL_ERROR;
416   }
417   zOut = p;
418   for(i=0; i<size; i++){
419     zOut[i] = zBin[i%n];
420   }
421   return TCL_OK;
422 }
423 
424 /*
425 ** Usage:    memget  ADDRESS  SIZE
426 **
427 ** Return memory as hexadecimal text.
428 */
test_memget(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])429 static int SQLITE_TCLAPI test_memget(
430   void * clientData,
431   Tcl_Interp *interp,
432   int objc,
433   Tcl_Obj *CONST objv[]
434 ){
435   void *p;
436   int size, n;
437   char *zBin;
438   char zHex[100];
439 
440   if( objc!=3 ){
441     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
442     return TCL_ERROR;
443   }
444   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
445     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
446     return TCL_ERROR;
447   }
448   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
449     return TCL_ERROR;
450   }
451   if( size<=0 ){
452     Tcl_AppendResult(interp, "size must be positive", (char*)0);
453     return TCL_ERROR;
454   }
455   zBin = p;
456   while( size>0 ){
457     if( size>(sizeof(zHex)-1)/2 ){
458       n = (sizeof(zHex)-1)/2;
459     }else{
460       n = size;
461     }
462     memcpy(zHex, zBin, n);
463     zBin += n;
464     size -= n;
465     sqlite3TestBinToHex(zHex, n);
466     Tcl_AppendResult(interp, zHex, (char*)0);
467   }
468   return TCL_OK;
469 }
470 
471 /*
472 ** Usage:    sqlite3_memory_used
473 **
474 ** Raw test interface for sqlite3_memory_used().
475 */
test_memory_used(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])476 static int SQLITE_TCLAPI test_memory_used(
477   void * clientData,
478   Tcl_Interp *interp,
479   int objc,
480   Tcl_Obj *CONST objv[]
481 ){
482   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
483   return TCL_OK;
484 }
485 
486 /*
487 ** Usage:    sqlite3_memory_highwater ?RESETFLAG?
488 **
489 ** Raw test interface for sqlite3_memory_highwater().
490 */
test_memory_highwater(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])491 static int SQLITE_TCLAPI test_memory_highwater(
492   void * clientData,
493   Tcl_Interp *interp,
494   int objc,
495   Tcl_Obj *CONST objv[]
496 ){
497   int resetFlag = 0;
498   if( objc!=1 && objc!=2 ){
499     Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
500     return TCL_ERROR;
501   }
502   if( objc==2 ){
503     if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
504   }
505   Tcl_SetObjResult(interp,
506      Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
507   return TCL_OK;
508 }
509 
510 /*
511 ** Usage:    sqlite3_memdebug_backtrace DEPTH
512 **
513 ** Set the depth of backtracing.  If SQLITE_MEMDEBUG is not defined
514 ** then this routine is a no-op.
515 */
test_memdebug_backtrace(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])516 static int SQLITE_TCLAPI test_memdebug_backtrace(
517   void * clientData,
518   Tcl_Interp *interp,
519   int objc,
520   Tcl_Obj *CONST objv[]
521 ){
522   int depth;
523   if( objc!=2 ){
524     Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
525     return TCL_ERROR;
526   }
527   if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
528 #ifdef SQLITE_MEMDEBUG
529   {
530     extern void sqlite3MemdebugBacktrace(int);
531     sqlite3MemdebugBacktrace(depth);
532   }
533 #endif
534   return TCL_OK;
535 }
536 
537 /*
538 ** Usage:    sqlite3_memdebug_dump  FILENAME
539 **
540 ** Write a summary of unfreed memory to FILENAME.
541 */
test_memdebug_dump(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])542 static int SQLITE_TCLAPI test_memdebug_dump(
543   void * clientData,
544   Tcl_Interp *interp,
545   int objc,
546   Tcl_Obj *CONST objv[]
547 ){
548   if( objc!=2 ){
549     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
550     return TCL_ERROR;
551   }
552 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
553      || defined(SQLITE_POW2_MEMORY_SIZE)
554   {
555     extern void sqlite3MemdebugDump(const char*);
556     sqlite3MemdebugDump(Tcl_GetString(objv[1]));
557   }
558 #endif
559   return TCL_OK;
560 }
561 
562 /*
563 ** Usage:    sqlite3_memdebug_malloc_count
564 **
565 ** Return the total number of times malloc() has been called.
566 */
test_memdebug_malloc_count(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])567 static int SQLITE_TCLAPI test_memdebug_malloc_count(
568   void * clientData,
569   Tcl_Interp *interp,
570   int objc,
571   Tcl_Obj *CONST objv[]
572 ){
573   int nMalloc = -1;
574   if( objc!=1 ){
575     Tcl_WrongNumArgs(interp, 1, objv, "");
576     return TCL_ERROR;
577   }
578 #if defined(SQLITE_MEMDEBUG)
579   {
580     extern int sqlite3MemdebugMallocCount();
581     nMalloc = sqlite3MemdebugMallocCount();
582   }
583 #endif
584   Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
585   return TCL_OK;
586 }
587 
588 
589 /*
590 ** Usage:    sqlite3_memdebug_fail  COUNTER  ?OPTIONS?
591 **
592 ** where options are:
593 **
594 **     -repeat    <count>
595 **     -benigncnt <varname>
596 **
597 ** Arrange for a simulated malloc() failure after COUNTER successes.
598 ** If a repeat count is specified, the fault is repeated that many
599 ** times.
600 **
601 ** Each call to this routine overrides the prior counter value.
602 ** This routine returns the number of simulated failures that have
603 ** happened since the previous call to this routine.
604 **
605 ** To disable simulated failures, use a COUNTER of -1.
606 */
test_memdebug_fail(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])607 static int SQLITE_TCLAPI test_memdebug_fail(
608   void * clientData,
609   Tcl_Interp *interp,
610   int objc,
611   Tcl_Obj *CONST objv[]
612 ){
613   int ii;
614   int iFail;
615   int nRepeat = 1;
616   Tcl_Obj *pBenignCnt = 0;
617   int nBenign;
618   int nFail = 0;
619 
620   if( objc<2 ){
621     Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
622     return TCL_ERROR;
623   }
624   if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
625 
626   for(ii=2; ii<objc; ii+=2){
627     int nOption;
628     char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
629     char *zErr = 0;
630 
631     if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
632       if( ii==(objc-1) ){
633         zErr = "option requires an argument: ";
634       }else{
635         if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
636           return TCL_ERROR;
637         }
638       }
639     }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
640       if( ii==(objc-1) ){
641         zErr = "option requires an argument: ";
642       }else{
643         pBenignCnt = objv[ii+1];
644       }
645     }else{
646       zErr = "unknown option: ";
647     }
648 
649     if( zErr ){
650       Tcl_AppendResult(interp, zErr, zOption, 0);
651       return TCL_ERROR;
652     }
653   }
654 
655   nBenign = faultsimBenignFailures();
656   nFail = faultsimFailures();
657   faultsimConfig(iFail, nRepeat);
658 
659   if( pBenignCnt ){
660     Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
661   }
662   Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
663   return TCL_OK;
664 }
665 
666 /*
667 ** Usage:    sqlite3_memdebug_pending
668 **
669 ** Return the number of malloc() calls that will succeed before a
670 ** simulated failure occurs. A negative return value indicates that
671 ** no malloc() failure is scheduled.
672 */
test_memdebug_pending(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])673 static int SQLITE_TCLAPI test_memdebug_pending(
674   void * clientData,
675   Tcl_Interp *interp,
676   int objc,
677   Tcl_Obj *CONST objv[]
678 ){
679   int nPending;
680   if( objc!=1 ){
681     Tcl_WrongNumArgs(interp, 1, objv, "");
682     return TCL_ERROR;
683   }
684   nPending = faultsimPending();
685   Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
686   return TCL_OK;
687 }
688 
689 /*
690 ** The following global variable keeps track of the number of tests
691 ** that have run.  This variable is only useful when running in the
692 ** debugger.
693 */
694 static int sqlite3_memdebug_title_count = 0;
695 
696 /*
697 ** Usage:    sqlite3_memdebug_settitle TITLE
698 **
699 ** Set a title string stored with each allocation.  The TITLE is
700 ** typically the name of the test that was running when the
701 ** allocation occurred.  The TITLE is stored with the allocation
702 ** and can be used to figure out which tests are leaking memory.
703 **
704 ** Each title overwrite the previous.
705 */
test_memdebug_settitle(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])706 static int SQLITE_TCLAPI test_memdebug_settitle(
707   void * clientData,
708   Tcl_Interp *interp,
709   int objc,
710   Tcl_Obj *CONST objv[]
711 ){
712   sqlite3_memdebug_title_count++;
713   if( objc!=2 ){
714     Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
715     return TCL_ERROR;
716   }
717 #ifdef SQLITE_MEMDEBUG
718   {
719     const char *zTitle;
720     extern int sqlite3MemdebugSettitle(const char*);
721     zTitle = Tcl_GetString(objv[1]);
722     sqlite3MemdebugSettitle(zTitle);
723   }
724 #endif
725   return TCL_OK;
726 }
727 
728 #define MALLOC_LOG_FRAMES  10
729 #define MALLOC_LOG_KEYINTS (                                              \
730     10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int))   \
731 )
732 static Tcl_HashTable aMallocLog;
733 static int mallocLogEnabled = 0;
734 
735 typedef struct MallocLog MallocLog;
736 struct MallocLog {
737   int nCall;
738   int nByte;
739 };
740 
741 #ifdef SQLITE_MEMDEBUG
test_memdebug_callback(int nByte,int nFrame,void ** aFrame)742 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
743   if( mallocLogEnabled ){
744     MallocLog *pLog;
745     Tcl_HashEntry *pEntry;
746     int isNew;
747 
748     int aKey[MALLOC_LOG_KEYINTS];
749     unsigned int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
750 
751     memset(aKey, 0, nKey);
752     if( (sizeof(void*)*nFrame)<nKey ){
753       nKey = nFrame*sizeof(void*);
754     }
755     memcpy(aKey, aFrame, nKey);
756 
757     pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
758     if( isNew ){
759       pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
760       memset(pLog, 0, sizeof(MallocLog));
761       Tcl_SetHashValue(pEntry, (ClientData)pLog);
762     }else{
763       pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
764     }
765 
766     pLog->nCall++;
767     pLog->nByte += nByte;
768   }
769 }
770 #endif /* SQLITE_MEMDEBUG */
771 
test_memdebug_log_clear(void)772 static void test_memdebug_log_clear(void){
773   Tcl_HashSearch search;
774   Tcl_HashEntry *pEntry;
775   for(
776     pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
777     pEntry;
778     pEntry=Tcl_NextHashEntry(&search)
779   ){
780     MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
781     Tcl_Free((char *)pLog);
782   }
783   Tcl_DeleteHashTable(&aMallocLog);
784   Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
785 }
786 
test_memdebug_log(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])787 static int SQLITE_TCLAPI test_memdebug_log(
788   void * clientData,
789   Tcl_Interp *interp,
790   int objc,
791   Tcl_Obj *CONST objv[]
792 ){
793   static int isInit = 0;
794   int iSub;
795 
796   static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
797   enum MB_enum {
798       MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
799   };
800 
801   if( !isInit ){
802 #ifdef SQLITE_MEMDEBUG
803     extern void sqlite3MemdebugBacktraceCallback(
804         void (*xBacktrace)(int, int, void **));
805     sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
806 #endif
807     Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
808     isInit = 1;
809   }
810 
811   if( objc<2 ){
812     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
813   }
814   if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
815     return TCL_ERROR;
816   }
817 
818   switch( (enum MB_enum)iSub ){
819     case MB_LOG_START:
820       mallocLogEnabled = 1;
821       break;
822     case MB_LOG_STOP:
823       mallocLogEnabled = 0;
824       break;
825     case MB_LOG_DUMP: {
826       Tcl_HashSearch search;
827       Tcl_HashEntry *pEntry;
828       Tcl_Obj *pRet = Tcl_NewObj();
829 
830       assert(sizeof(Tcl_WideInt)>=sizeof(void*));
831 
832       for(
833         pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
834         pEntry;
835         pEntry=Tcl_NextHashEntry(&search)
836       ){
837         Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
838         MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
839         Tcl_WideInt *aKey = (Tcl_WideInt *)Tcl_GetHashKey(&aMallocLog, pEntry);
840         int ii;
841 
842         apElem[0] = Tcl_NewIntObj(pLog->nCall);
843         apElem[1] = Tcl_NewIntObj(pLog->nByte);
844         for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
845           apElem[ii+2] = Tcl_NewWideIntObj(aKey[ii]);
846         }
847 
848         Tcl_ListObjAppendElement(interp, pRet,
849             Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
850         );
851       }
852 
853       Tcl_SetObjResult(interp, pRet);
854       break;
855     }
856     case MB_LOG_CLEAR: {
857       test_memdebug_log_clear();
858       break;
859     }
860 
861     case MB_LOG_SYNC: {
862 #ifdef SQLITE_MEMDEBUG
863       extern void sqlite3MemdebugSync();
864       test_memdebug_log_clear();
865       mallocLogEnabled = 1;
866       sqlite3MemdebugSync();
867 #endif
868       break;
869     }
870   }
871 
872   return TCL_OK;
873 }
874 
875 /*
876 ** Usage:    sqlite3_config_pagecache SIZE N
877 **
878 ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
879 ** The buffer is static and is of limited size.  N might be
880 ** adjusted downward as needed to accommodate the requested size.
881 ** The revised value of N is returned.
882 **
883 ** A negative SIZE causes the buffer pointer to be NULL.
884 */
test_config_pagecache(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])885 static int SQLITE_TCLAPI test_config_pagecache(
886   void * clientData,
887   Tcl_Interp *interp,
888   int objc,
889   Tcl_Obj *CONST objv[]
890 ){
891   int sz, N;
892   Tcl_Obj *pRes;
893   static char *buf = 0;
894   if( objc!=3 ){
895     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
896     return TCL_ERROR;
897   }
898   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
899   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
900   free(buf);
901   buf = 0;
902 
903   /* Set the return value */
904   pRes = Tcl_NewObj();
905   Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.szPage));
906   Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.nPage));
907   Tcl_SetObjResult(interp, pRes);
908 
909   if( sz<0 ){
910     sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, 0);
911   }else{
912     buf = malloc( sz*N );
913     sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
914   }
915   return TCL_OK;
916 }
917 
918 /*
919 ** Usage:    sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
920 **
921 ** Set up the alternative test page cache.  Install if INSTALL_FLAG is
922 ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
923 ** is false.  DISCARD_CHANGE is an integer between 0 and 100 inclusive
924 ** which determines the chance of discarding a page when unpinned.  100
925 ** is certainty.  0 is never.  PRNG_SEED is the pseudo-random number generator
926 ** seed.
927 */
test_alt_pcache(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])928 static int SQLITE_TCLAPI test_alt_pcache(
929   void * clientData,
930   Tcl_Interp *interp,
931   int objc,
932   Tcl_Obj *CONST objv[]
933 ){
934   int installFlag;
935   int discardChance = 0;
936   int prngSeed = 0;
937   int highStress = 0;
938   extern void installTestPCache(int,unsigned,unsigned,unsigned);
939   if( objc<2 || objc>5 ){
940     Tcl_WrongNumArgs(interp, 1, objv,
941         "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
942     return TCL_ERROR;
943   }
944   if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
945   if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){
946      return TCL_ERROR;
947   }
948   if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){
949      return TCL_ERROR;
950   }
951   if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){
952     return TCL_ERROR;
953   }
954   if( discardChance<0 || discardChance>100 ){
955     Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
956                      (char*)0);
957     return TCL_ERROR;
958   }
959   installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,
960                     (unsigned)highStress);
961   return TCL_OK;
962 }
963 
964 /*
965 ** Usage:    sqlite3_config_memstatus BOOLEAN
966 **
967 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
968 */
test_config_memstatus(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])969 static int SQLITE_TCLAPI test_config_memstatus(
970   void * clientData,
971   Tcl_Interp *interp,
972   int objc,
973   Tcl_Obj *CONST objv[]
974 ){
975   int enable, rc;
976   if( objc!=2 ){
977     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
978     return TCL_ERROR;
979   }
980   if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
981   rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
982   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
983   return TCL_OK;
984 }
985 
986 /*
987 ** Usage:    sqlite3_config_lookaside  SIZE  COUNT
988 **
989 */
test_config_lookaside(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])990 static int SQLITE_TCLAPI test_config_lookaside(
991   void * clientData,
992   Tcl_Interp *interp,
993   int objc,
994   Tcl_Obj *CONST objv[]
995 ){
996   int sz, cnt;
997   Tcl_Obj *pRet;
998   if( objc!=3 ){
999     Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1000     return TCL_ERROR;
1001   }
1002   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1003   if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
1004   pRet = Tcl_NewObj();
1005   Tcl_ListObjAppendElement(
1006       interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)
1007   );
1008   Tcl_ListObjAppendElement(
1009       interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)
1010   );
1011   sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
1012   Tcl_SetObjResult(interp, pRet);
1013   return TCL_OK;
1014 }
1015 
1016 
1017 /*
1018 ** Usage:    sqlite3_db_config_lookaside  CONNECTION  BUFID  SIZE  COUNT
1019 **
1020 ** There are two static buffers with BUFID 1 and 2.   Each static buffer
1021 ** is 10KB in size.  A BUFID of 0 indicates that the buffer should be NULL
1022 ** which will cause sqlite3_db_config() to allocate space on its own.
1023 */
test_db_config_lookaside(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1024 static int SQLITE_TCLAPI test_db_config_lookaside(
1025   void * clientData,
1026   Tcl_Interp *interp,
1027   int objc,
1028   Tcl_Obj *CONST objv[]
1029 ){
1030   int rc;
1031   int sz, cnt;
1032   sqlite3 *db;
1033   int bufid;
1034   static char azBuf[2][10000];
1035   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1036   if( objc!=5 ){
1037     Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
1038     return TCL_ERROR;
1039   }
1040   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1041   if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
1042   if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
1043   if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
1044   if( bufid==0 ){
1045     rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, (void*)0, sz, cnt);
1046   }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
1047     rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
1048   }else{
1049     Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
1050     return TCL_ERROR;
1051   }
1052   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1053   return TCL_OK;
1054 }
1055 
1056 /*
1057 ** Usage:    sqlite3_config_heap NBYTE NMINALLOC
1058 */
test_config_heap(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1059 static int SQLITE_TCLAPI test_config_heap(
1060   void * clientData,
1061   Tcl_Interp *interp,
1062   int objc,
1063   Tcl_Obj *CONST objv[]
1064 ){
1065   static char *zBuf; /* Use this memory */
1066   int nByte;         /* Size of buffer to pass to sqlite3_config() */
1067   int nMinAlloc;     /* Size of minimum allocation */
1068   int rc;            /* Return code of sqlite3_config() */
1069 
1070   Tcl_Obj * CONST *aArg = &objv[1];
1071   int nArg = objc-1;
1072 
1073   if( nArg!=2 ){
1074     Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
1075     return TCL_ERROR;
1076   }
1077   if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1078   if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
1079 
1080   if( nByte==0 ){
1081     free( zBuf );
1082     zBuf = 0;
1083     rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
1084   }else{
1085     zBuf = realloc(zBuf, nByte);
1086     rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
1087   }
1088 
1089   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1090   return TCL_OK;
1091 }
1092 
1093 /*
1094 ** Usage:    sqlite3_config_heap_size NBYTE
1095 */
test_config_heap_size(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1096 static int SQLITE_TCLAPI test_config_heap_size(
1097   void * clientData,
1098   Tcl_Interp *interp,
1099   int objc,
1100   Tcl_Obj *CONST objv[]
1101 ){
1102   int nByte;         /* Size to pass to sqlite3_config() */
1103   int rc;            /* Return code of sqlite3_config() */
1104 
1105   Tcl_Obj * CONST *aArg = &objv[1];
1106   int nArg = objc-1;
1107 
1108   if( nArg!=1 ){
1109     Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
1110     return TCL_ERROR;
1111   }
1112   if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1113 
1114   rc = sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE, nByte);
1115 
1116   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1117   return TCL_OK;
1118 }
1119 
1120 /*
1121 ** Usage:    sqlite3_config_error  [DB]
1122 **
1123 ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1124 ** opcodes and verify that they return errors.
1125 */
test_config_error(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1126 static int SQLITE_TCLAPI test_config_error(
1127   void * clientData,
1128   Tcl_Interp *interp,
1129   int objc,
1130   Tcl_Obj *CONST objv[]
1131 ){
1132   sqlite3 *db;
1133   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1134 
1135   if( objc!=2 && objc!=1 ){
1136     Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
1137     return TCL_ERROR;
1138   }
1139   if( objc==2 ){
1140     if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1141     if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
1142       Tcl_AppendResult(interp,
1143             "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
1144             (char*)0);
1145       return TCL_ERROR;
1146     }
1147   }else{
1148     if( sqlite3_config(99999)!=SQLITE_ERROR ){
1149       Tcl_AppendResult(interp,
1150           "sqlite3_config(99999) does not return SQLITE_ERROR",
1151           (char*)0);
1152       return TCL_ERROR;
1153     }
1154   }
1155   return TCL_OK;
1156 }
1157 
1158 /*
1159 ** Usage:    sqlite3_config_uri  BOOLEAN
1160 **
1161 ** Enables or disables interpretation of URI parameters by default using
1162 ** SQLITE_CONFIG_URI.
1163 */
test_config_uri(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1164 static int SQLITE_TCLAPI test_config_uri(
1165   void * clientData,
1166   Tcl_Interp *interp,
1167   int objc,
1168   Tcl_Obj *CONST objv[]
1169 ){
1170   int rc;
1171   int bOpenUri;
1172 
1173   if( objc!=2 ){
1174     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1175     return TCL_ERROR;
1176   }
1177   if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){
1178     return TCL_ERROR;
1179   }
1180 
1181   rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);
1182   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1183 
1184   return TCL_OK;
1185 }
1186 
1187 /*
1188 ** Usage:    sqlite3_config_cis  BOOLEAN
1189 **
1190 ** Enables or disables the use of the covering-index scan optimization.
1191 ** SQLITE_CONFIG_COVERING_INDEX_SCAN.
1192 */
test_config_cis(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1193 static int SQLITE_TCLAPI test_config_cis(
1194   void * clientData,
1195   Tcl_Interp *interp,
1196   int objc,
1197   Tcl_Obj *CONST objv[]
1198 ){
1199   int rc;
1200   int bUseCis;
1201 
1202   if( objc!=2 ){
1203     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1204     return TCL_ERROR;
1205   }
1206   if( Tcl_GetBooleanFromObj(interp, objv[1], &bUseCis) ){
1207     return TCL_ERROR;
1208   }
1209 
1210   rc = sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN, bUseCis);
1211   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1212 
1213   return TCL_OK;
1214 }
1215 
1216 /*
1217 ** Usage:    sqlite3_config_pmasz  INTEGER
1218 **
1219 ** Set the minimum PMA size.
1220 */
test_config_pmasz(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1221 static int SQLITE_TCLAPI test_config_pmasz(
1222   void * clientData,
1223   Tcl_Interp *interp,
1224   int objc,
1225   Tcl_Obj *CONST objv[]
1226 ){
1227   int rc;
1228   int iPmaSz;
1229 
1230   if( objc!=2 ){
1231     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1232     return TCL_ERROR;
1233   }
1234   if( Tcl_GetIntFromObj(interp, objv[1], &iPmaSz) ){
1235     return TCL_ERROR;
1236   }
1237 
1238   rc = sqlite3_config(SQLITE_CONFIG_PMASZ, iPmaSz);
1239   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1240 
1241   return TCL_OK;
1242 }
1243 
1244 
1245 /*
1246 ** Usage:    sqlite3_dump_memsys3  FILENAME
1247 **           sqlite3_dump_memsys5  FILENAME
1248 **
1249 ** Write a summary of unfreed memsys3 allocations to FILENAME.
1250 */
test_dump_memsys3(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1251 static int SQLITE_TCLAPI test_dump_memsys3(
1252   void * clientData,
1253   Tcl_Interp *interp,
1254   int objc,
1255   Tcl_Obj *CONST objv[]
1256 ){
1257   if( objc!=2 ){
1258     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
1259     return TCL_ERROR;
1260   }
1261 
1262   switch( SQLITE_PTR_TO_INT(clientData) ){
1263     case 3: {
1264 #ifdef SQLITE_ENABLE_MEMSYS3
1265       extern void sqlite3Memsys3Dump(const char*);
1266       sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1267       break;
1268 #endif
1269     }
1270     case 5: {
1271 #ifdef SQLITE_ENABLE_MEMSYS5
1272       extern void sqlite3Memsys5Dump(const char*);
1273       sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1274       break;
1275 #endif
1276     }
1277   }
1278   return TCL_OK;
1279 }
1280 
1281 /*
1282 ** Usage:    sqlite3_status  OPCODE  RESETFLAG
1283 **
1284 ** Return a list of three elements which are the sqlite3_status() return
1285 ** code, the current value, and the high-water mark value.
1286 */
test_status(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1287 static int SQLITE_TCLAPI test_status(
1288   void * clientData,
1289   Tcl_Interp *interp,
1290   int objc,
1291   Tcl_Obj *CONST objv[]
1292 ){
1293   int rc, iValue, mxValue;
1294   int i, op = 0, resetFlag;
1295   const char *zOpName;
1296   static const struct {
1297     const char *zName;
1298     int op;
1299   } aOp[] = {
1300     { "SQLITE_STATUS_MEMORY_USED",         SQLITE_STATUS_MEMORY_USED         },
1301     { "SQLITE_STATUS_MALLOC_SIZE",         SQLITE_STATUS_MALLOC_SIZE         },
1302     { "SQLITE_STATUS_PAGECACHE_USED",      SQLITE_STATUS_PAGECACHE_USED      },
1303     { "SQLITE_STATUS_PAGECACHE_OVERFLOW",  SQLITE_STATUS_PAGECACHE_OVERFLOW  },
1304     { "SQLITE_STATUS_PAGECACHE_SIZE",      SQLITE_STATUS_PAGECACHE_SIZE      },
1305     { "SQLITE_STATUS_SCRATCH_USED",        SQLITE_STATUS_SCRATCH_USED        },
1306     { "SQLITE_STATUS_SCRATCH_OVERFLOW",    SQLITE_STATUS_SCRATCH_OVERFLOW    },
1307     { "SQLITE_STATUS_SCRATCH_SIZE",        SQLITE_STATUS_SCRATCH_SIZE        },
1308     { "SQLITE_STATUS_PARSER_STACK",        SQLITE_STATUS_PARSER_STACK        },
1309     { "SQLITE_STATUS_MALLOC_COUNT",        SQLITE_STATUS_MALLOC_COUNT        },
1310   };
1311   Tcl_Obj *pResult;
1312   if( objc!=3 ){
1313     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1314     return TCL_ERROR;
1315   }
1316   zOpName = Tcl_GetString(objv[1]);
1317   for(i=0; i<ArraySize(aOp); i++){
1318     if( strcmp(aOp[i].zName, zOpName)==0 ){
1319       op = aOp[i].op;
1320       break;
1321     }
1322   }
1323   if( i>=ArraySize(aOp) ){
1324     if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1325   }
1326   if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
1327   iValue = 0;
1328   mxValue = 0;
1329   rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1330   pResult = Tcl_NewObj();
1331   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1332   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1333   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1334   Tcl_SetObjResult(interp, pResult);
1335   return TCL_OK;
1336 }
1337 
1338 /*
1339 ** Usage:    sqlite3_db_status  DATABASE  OPCODE  RESETFLAG
1340 **
1341 ** Return a list of three elements which are the sqlite3_db_status() return
1342 ** code, the current value, and the high-water mark value.
1343 */
test_db_status(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1344 static int SQLITE_TCLAPI test_db_status(
1345   void * clientData,
1346   Tcl_Interp *interp,
1347   int objc,
1348   Tcl_Obj *CONST objv[]
1349 ){
1350   int rc, iValue, mxValue;
1351   int i, op = 0, resetFlag;
1352   const char *zOpName;
1353   sqlite3 *db;
1354   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1355   static const struct {
1356     const char *zName;
1357     int op;
1358   } aOp[] = {
1359     { "LOOKASIDE_USED",      SQLITE_DBSTATUS_LOOKASIDE_USED      },
1360     { "CACHE_USED",          SQLITE_DBSTATUS_CACHE_USED          },
1361     { "SCHEMA_USED",         SQLITE_DBSTATUS_SCHEMA_USED         },
1362     { "STMT_USED",           SQLITE_DBSTATUS_STMT_USED           },
1363     { "LOOKASIDE_HIT",       SQLITE_DBSTATUS_LOOKASIDE_HIT       },
1364     { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE },
1365     { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL },
1366     { "CACHE_HIT",           SQLITE_DBSTATUS_CACHE_HIT           },
1367     { "CACHE_MISS",          SQLITE_DBSTATUS_CACHE_MISS          },
1368     { "CACHE_WRITE",         SQLITE_DBSTATUS_CACHE_WRITE         },
1369     { "DEFERRED_FKS",        SQLITE_DBSTATUS_DEFERRED_FKS        },
1370     { "CACHE_USED_SHARED",   SQLITE_DBSTATUS_CACHE_USED_SHARED   },
1371     { "CACHE_SPILL",         SQLITE_DBSTATUS_CACHE_SPILL         },
1372   };
1373   Tcl_Obj *pResult;
1374   if( objc!=4 ){
1375     Tcl_WrongNumArgs(interp, 1, objv, "DB PARAMETER RESETFLAG");
1376     return TCL_ERROR;
1377   }
1378   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1379   zOpName = Tcl_GetString(objv[2]);
1380   if( memcmp(zOpName, "SQLITE_", 7)==0 ) zOpName += 7;
1381   if( memcmp(zOpName, "DBSTATUS_", 9)==0 ) zOpName += 9;
1382   for(i=0; i<ArraySize(aOp); i++){
1383     if( strcmp(aOp[i].zName, zOpName)==0 ){
1384       op = aOp[i].op;
1385       break;
1386     }
1387   }
1388   if( i>=ArraySize(aOp) ){
1389     if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1390   }
1391   if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1392   iValue = 0;
1393   mxValue = 0;
1394   rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1395   pResult = Tcl_NewObj();
1396   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1397   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1398   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1399   Tcl_SetObjResult(interp, pResult);
1400   return TCL_OK;
1401 }
1402 
1403 /*
1404 ** install_malloc_faultsim BOOLEAN
1405 */
test_install_malloc_faultsim(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1406 static int SQLITE_TCLAPI test_install_malloc_faultsim(
1407   void * clientData,
1408   Tcl_Interp *interp,
1409   int objc,
1410   Tcl_Obj *CONST objv[]
1411 ){
1412   int rc;
1413   int isInstall;
1414 
1415   if( objc!=2 ){
1416     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1417     return TCL_ERROR;
1418   }
1419   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1420     return TCL_ERROR;
1421   }
1422   rc = faultsimInstall(isInstall);
1423   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1424   return TCL_OK;
1425 }
1426 
1427 /*
1428 ** sqlite3_install_memsys3
1429 */
test_install_memsys3(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1430 static int SQLITE_TCLAPI test_install_memsys3(
1431   void * clientData,
1432   Tcl_Interp *interp,
1433   int objc,
1434   Tcl_Obj *CONST objv[]
1435 ){
1436   int rc = SQLITE_MISUSE;
1437 #ifdef SQLITE_ENABLE_MEMSYS3
1438   const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
1439   rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3());
1440 #endif
1441   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1442   return TCL_OK;
1443 }
1444 
test_vfs_oom_test(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])1445 static int SQLITE_TCLAPI test_vfs_oom_test(
1446   void * clientData,
1447   Tcl_Interp *interp,
1448   int objc,
1449   Tcl_Obj *CONST objv[]
1450 ){
1451   extern int sqlite3_memdebug_vfs_oom_test;
1452   if( objc>2 ){
1453     Tcl_WrongNumArgs(interp, 1, objv, "?INTEGER?");
1454     return TCL_ERROR;
1455   }else if( objc==2 ){
1456     int iNew;
1457     if( Tcl_GetIntFromObj(interp, objv[1], &iNew) ) return TCL_ERROR;
1458     sqlite3_memdebug_vfs_oom_test = iNew;
1459   }
1460   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test));
1461   return TCL_OK;
1462 }
1463 
1464 /*
1465 ** Register commands with the TCL interpreter.
1466 */
Sqlitetest_malloc_Init(Tcl_Interp * interp)1467 int Sqlitetest_malloc_Init(Tcl_Interp *interp){
1468   static struct {
1469      char *zName;
1470      Tcl_ObjCmdProc *xProc;
1471      int clientData;
1472   } aObjCmd[] = {
1473      { "sqlite3_malloc",             test_malloc                   ,0 },
1474      { "sqlite3_realloc",            test_realloc                  ,0 },
1475      { "sqlite3_free",               test_free                     ,0 },
1476      { "memset",                     test_memset                   ,0 },
1477      { "memget",                     test_memget                   ,0 },
1478      { "sqlite3_memory_used",        test_memory_used              ,0 },
1479      { "sqlite3_memory_highwater",   test_memory_highwater         ,0 },
1480      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       ,0 },
1481      { "sqlite3_memdebug_dump",      test_memdebug_dump            ,0 },
1482      { "sqlite3_memdebug_fail",      test_memdebug_fail            ,0 },
1483      { "sqlite3_memdebug_pending",   test_memdebug_pending         ,0 },
1484      { "sqlite3_memdebug_settitle",  test_memdebug_settitle        ,0 },
1485      { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
1486      { "sqlite3_memdebug_log",       test_memdebug_log             ,0 },
1487      { "sqlite3_config_pagecache",   test_config_pagecache         ,0 },
1488      { "sqlite3_config_alt_pcache",  test_alt_pcache               ,0 },
1489      { "sqlite3_status",             test_status                   ,0 },
1490      { "sqlite3_db_status",          test_db_status                ,0 },
1491      { "install_malloc_faultsim",    test_install_malloc_faultsim  ,0 },
1492      { "sqlite3_config_heap",        test_config_heap              ,0 },
1493      { "sqlite3_config_heap_size",   test_config_heap_size         ,0 },
1494      { "sqlite3_config_memstatus",   test_config_memstatus         ,0 },
1495      { "sqlite3_config_lookaside",   test_config_lookaside         ,0 },
1496      { "sqlite3_config_error",       test_config_error             ,0 },
1497      { "sqlite3_config_uri",         test_config_uri               ,0 },
1498      { "sqlite3_config_cis",         test_config_cis               ,0 },
1499      { "sqlite3_config_pmasz",       test_config_pmasz             ,0 },
1500      { "sqlite3_db_config_lookaside",test_db_config_lookaside      ,0 },
1501      { "sqlite3_dump_memsys3",       test_dump_memsys3             ,3 },
1502      { "sqlite3_dump_memsys5",       test_dump_memsys3             ,5 },
1503      { "sqlite3_install_memsys3",    test_install_memsys3          ,0 },
1504      { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test          ,0 },
1505   };
1506   int i;
1507   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
1508     ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);
1509     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
1510   }
1511   return TCL_OK;
1512 }
1513 #endif
1514