blob: 7519b5f7a231553d54543ecb597fef3657f64c01 [file] [log] [blame]
drh2f999a62007-08-15 19:16:43 +00001/*
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**
drhf2a84e32009-01-07 03:59:47 +000016** $Id: test_malloc.c,v 1.52 2009/01/07 03:59:47 drh Exp $
drh2f999a62007-08-15 19:16:43 +000017*/
18#include "sqliteInt.h"
19#include "tcl.h"
20#include <stdlib.h>
21#include <string.h>
22#include <assert.h>
23
danielk1977ef05f2d2008-06-20 11:05:37 +000024/*
25** This structure is used to encapsulate the global state variables used
26** by malloc() fault simulation.
27*/
28static struct MemFault {
29 int iCountdown; /* Number of pending successes before a failure */
30 int nRepeat; /* Number of times to repeat the failure */
31 int nBenign; /* Number of benign failures seen since last config */
32 int nFail; /* Number of failures seen since last config */
33 u8 enable; /* True if enabled */
34 int isInstalled; /* True if the fault simulation layer is installed */
danielk19772d1d86f2008-06-20 14:59:51 +000035 int isBenignMode; /* True if malloc failures are considered benign */
danielk1977ef05f2d2008-06-20 11:05:37 +000036 sqlite3_mem_methods m; /* 'Real' malloc implementation */
37} memfault;
38
39/*
40** This routine exists as a place to set a breakpoint that will
41** fire on any simulated malloc() failure.
42*/
43static void sqlite3Fault(void){
44 static int cnt = 0;
45 cnt++;
46}
47
48/*
49** Check to see if a fault should be simulated. Return true to simulate
50** the fault. Return false if the fault should not be simulated.
51*/
52static int faultsimStep(){
53 if( likely(!memfault.enable) ){
54 return 0;
55 }
56 if( memfault.iCountdown>0 ){
57 memfault.iCountdown--;
58 return 0;
59 }
60 sqlite3Fault();
61 memfault.nFail++;
danielk19772d1d86f2008-06-20 14:59:51 +000062 if( memfault.isBenignMode>0 ){
danielk1977ef05f2d2008-06-20 11:05:37 +000063 memfault.nBenign++;
64 }
65 memfault.nRepeat--;
66 if( memfault.nRepeat<=0 ){
67 memfault.enable = 0;
68 }
69 return 1;
70}
71
72/*
73** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
74** logic.
75*/
76static void *faultsimMalloc(int n){
77 void *p = 0;
78 if( !faultsimStep() ){
79 p = memfault.m.xMalloc(n);
80 }
81 return p;
82}
83
84
85/*
86** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
87** logic.
88*/
89static void *faultsimRealloc(void *pOld, int n){
90 void *p = 0;
91 if( !faultsimStep() ){
92 p = memfault.m.xRealloc(pOld, n);
93 }
94 return p;
95}
96
97/*
98** The following method calls are passed directly through to the underlying
99** malloc system:
100**
101** xFree
102** xSize
103** xRoundup
104** xInit
105** xShutdown
106*/
107static void faultsimFree(void *p){
108 memfault.m.xFree(p);
109}
110static int faultsimSize(void *p){
111 return memfault.m.xSize(p);
112}
113static int faultsimRoundup(int n){
114 return memfault.m.xRoundup(n);
115}
116static int faultsimInit(void *p){
117 return memfault.m.xInit(memfault.m.pAppData);
118}
119static void faultsimShutdown(void *p){
120 memfault.m.xShutdown(memfault.m.pAppData);
121}
122
123/*
124** This routine configures the malloc failure simulation. After
125** calling this routine, the next nDelay mallocs will succeed, followed
126** by a block of nRepeat failures, after which malloc() calls will begin
127** to succeed again.
128*/
129static void faultsimConfig(int nDelay, int nRepeat){
130 memfault.iCountdown = nDelay;
131 memfault.nRepeat = nRepeat;
132 memfault.nBenign = 0;
133 memfault.nFail = 0;
134 memfault.enable = nDelay>=0;
135}
136
137/*
138** Return the number of faults (both hard and benign faults) that have
139** occurred since the injector was last configured.
140*/
141static int faultsimFailures(void){
142 return memfault.nFail;
143}
144
145/*
146** Return the number of benign faults that have occurred since the
147** injector was last configured.
148*/
149static int faultsimBenignFailures(void){
150 return memfault.nBenign;
151}
152
153/*
154** Return the number of successes that will occur before the next failure.
155** If no failures are scheduled, return -1.
156*/
157static int faultsimPending(void){
158 if( memfault.enable ){
159 return memfault.iCountdown;
160 }else{
161 return -1;
162 }
163}
164
danielk19772d1d86f2008-06-20 14:59:51 +0000165
166static void faultsimBeginBenign(void){
167 memfault.isBenignMode++;
168}
169static void faultsimEndBenign(void){
170 memfault.isBenignMode--;
171}
172
danielk1977ef05f2d2008-06-20 11:05:37 +0000173/*
174** Add or remove the fault-simulation layer using sqlite3_config(). If
175** the argument is non-zero, the
176*/
177static int faultsimInstall(int install){
178 static struct sqlite3_mem_methods m = {
179 faultsimMalloc, /* xMalloc */
180 faultsimFree, /* xFree */
181 faultsimRealloc, /* xRealloc */
182 faultsimSize, /* xSize */
183 faultsimRoundup, /* xRoundup */
184 faultsimInit, /* xInit */
185 faultsimShutdown, /* xShutdown */
186 0 /* pAppData */
187 };
188 int rc;
189
190 install = (install ? 1 : 0);
191 assert(memfault.isInstalled==1 || memfault.isInstalled==0);
192
193 if( install==memfault.isInstalled ){
194 return SQLITE_ERROR;
195 }
196
danielk19772d1d86f2008-06-20 14:59:51 +0000197 if( install ){
198 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
199 assert(memfault.m.xMalloc);
200 if( rc==SQLITE_OK ){
201 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
202 }
203 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
204 faultsimBeginBenign, faultsimEndBenign
205 );
206 }else{
drh1b67f3c2008-10-10 17:41:28 +0000207 sqlite3_mem_methods m;
danielk19772d1d86f2008-06-20 14:59:51 +0000208 assert(memfault.m.xMalloc);
drh1b67f3c2008-10-10 17:41:28 +0000209
210 /* One should be able to reset the default memory allocator by storing
211 ** a zeroed allocator then calling GETMALLOC. */
212 memset(&m, 0, sizeof(m));
213 sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
214 sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m);
215 assert( memcmp(&m, &memfault.m, sizeof(m))==0 );
216
danielk19772d1d86f2008-06-20 14:59:51 +0000217 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
218 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0);
danielk1977ef05f2d2008-06-20 11:05:37 +0000219 }
220
221 if( rc==SQLITE_OK ){
222 memfault.isInstalled = 1;
223 }
224 return rc;
225}
226
227#ifdef SQLITE_TEST
228
229/*
230** This function is implemented in test1.c. Returns a pointer to a static
231** buffer containing the symbolic SQLite error code that corresponds to
232** the least-significant 8-bits of the integer passed as an argument.
233** For example:
234**
235** sqlite3TestErrorName(1) -> "SQLITE_ERROR"
236*/
danielk1977d09414c2008-06-19 18:17:49 +0000237const char *sqlite3TestErrorName(int);
238
drh2f999a62007-08-15 19:16:43 +0000239/*
240** Transform pointers to text and back again
241*/
242static void pointerToText(void *p, char *z){
243 static const char zHex[] = "0123456789abcdef";
244 int i, k;
drh4a50aac2007-08-23 02:47:53 +0000245 unsigned int u;
246 sqlite3_uint64 n;
drh8a42cbd2008-07-10 18:13:42 +0000247 if( p==0 ){
248 strcpy(z, "0");
249 return;
250 }
drh4a50aac2007-08-23 02:47:53 +0000251 if( sizeof(n)==sizeof(p) ){
252 memcpy(&n, &p, sizeof(p));
253 }else if( sizeof(u)==sizeof(p) ){
254 memcpy(&u, &p, sizeof(u));
255 n = u;
256 }else{
257 assert( 0 );
258 }
drh2f999a62007-08-15 19:16:43 +0000259 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
260 z[k] = zHex[n&0xf];
261 n >>= 4;
262 }
263 z[sizeof(p)*2] = 0;
264}
265static int hexToInt(int h){
266 if( h>='0' && h<='9' ){
267 return h - '0';
268 }else if( h>='a' && h<='f' ){
269 return h - 'a' + 10;
270 }else{
271 return -1;
272 }
273}
274static int textToPointer(const char *z, void **pp){
275 sqlite3_uint64 n = 0;
276 int i;
drh4a50aac2007-08-23 02:47:53 +0000277 unsigned int u;
drh2f999a62007-08-15 19:16:43 +0000278 for(i=0; i<sizeof(void*)*2 && z[0]; i++){
279 int v;
280 v = hexToInt(*z++);
281 if( v<0 ) return TCL_ERROR;
282 n = n*16 + v;
283 }
284 if( *z!=0 ) return TCL_ERROR;
drh4a50aac2007-08-23 02:47:53 +0000285 if( sizeof(n)==sizeof(*pp) ){
286 memcpy(pp, &n, sizeof(n));
287 }else if( sizeof(u)==sizeof(*pp) ){
288 u = (unsigned int)n;
289 memcpy(pp, &u, sizeof(u));
290 }else{
291 assert( 0 );
292 }
drh2f999a62007-08-15 19:16:43 +0000293 return TCL_OK;
294}
295
296/*
297** Usage: sqlite3_malloc NBYTES
298**
299** Raw test interface for sqlite3_malloc().
300*/
301static int test_malloc(
302 void * clientData,
303 Tcl_Interp *interp,
304 int objc,
305 Tcl_Obj *CONST objv[]
306){
307 int nByte;
308 void *p;
309 char zOut[100];
310 if( objc!=2 ){
311 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
312 return TCL_ERROR;
313 }
314 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
315 p = sqlite3_malloc((unsigned)nByte);
316 pointerToText(p, zOut);
317 Tcl_AppendResult(interp, zOut, NULL);
318 return TCL_OK;
319}
320
321/*
322** Usage: sqlite3_realloc PRIOR NBYTES
323**
324** Raw test interface for sqlite3_realloc().
325*/
326static int test_realloc(
327 void * clientData,
328 Tcl_Interp *interp,
329 int objc,
330 Tcl_Obj *CONST objv[]
331){
332 int nByte;
333 void *pPrior, *p;
334 char zOut[100];
335 if( objc!=3 ){
336 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
337 return TCL_ERROR;
338 }
339 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
340 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
341 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
342 return TCL_ERROR;
343 }
344 p = sqlite3_realloc(pPrior, (unsigned)nByte);
345 pointerToText(p, zOut);
346 Tcl_AppendResult(interp, zOut, NULL);
347 return TCL_OK;
348}
349
drh2f999a62007-08-15 19:16:43 +0000350/*
351** Usage: sqlite3_free PRIOR
352**
353** Raw test interface for sqlite3_free().
354*/
355static int test_free(
356 void * clientData,
357 Tcl_Interp *interp,
358 int objc,
359 Tcl_Obj *CONST objv[]
360){
361 void *pPrior;
362 if( objc!=2 ){
363 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
364 return TCL_ERROR;
365 }
366 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
367 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
368 return TCL_ERROR;
369 }
370 sqlite3_free(pPrior);
371 return TCL_OK;
372}
373
374/*
drh9c7a60d2007-10-19 17:47:24 +0000375** These routines are in test_hexio.c
376*/
377int sqlite3TestHexToBin(const char *, int, char *);
378int sqlite3TestBinToHex(char*,int);
379
380/*
381** Usage: memset ADDRESS SIZE HEX
382**
383** Set a chunk of memory (obtained from malloc, probably) to a
384** specified hex pattern.
385*/
386static int test_memset(
387 void * clientData,
388 Tcl_Interp *interp,
389 int objc,
390 Tcl_Obj *CONST objv[]
391){
392 void *p;
393 int size, n, i;
394 char *zHex;
395 char *zOut;
396 char zBin[100];
397
398 if( objc!=4 ){
399 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
400 return TCL_ERROR;
401 }
402 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
403 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
404 return TCL_ERROR;
405 }
406 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
407 return TCL_ERROR;
408 }
409 if( size<=0 ){
410 Tcl_AppendResult(interp, "size must be positive", (char*)0);
411 return TCL_ERROR;
412 }
413 zHex = Tcl_GetStringFromObj(objv[3], &n);
414 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
415 n = sqlite3TestHexToBin(zHex, n, zBin);
416 if( n==0 ){
417 Tcl_AppendResult(interp, "no data", (char*)0);
418 return TCL_ERROR;
419 }
420 zOut = p;
421 for(i=0; i<size; i++){
422 zOut[i] = zBin[i%n];
423 }
424 return TCL_OK;
425}
426
427/*
428** Usage: memget ADDRESS SIZE
429**
430** Return memory as hexadecimal text.
431*/
432static int test_memget(
433 void * clientData,
434 Tcl_Interp *interp,
435 int objc,
436 Tcl_Obj *CONST objv[]
437){
438 void *p;
439 int size, n;
440 char *zBin;
441 char zHex[100];
442
443 if( objc!=3 ){
444 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
445 return TCL_ERROR;
446 }
447 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
448 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
449 return TCL_ERROR;
450 }
451 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
452 return TCL_ERROR;
453 }
454 if( size<=0 ){
455 Tcl_AppendResult(interp, "size must be positive", (char*)0);
456 return TCL_ERROR;
457 }
458 zBin = p;
459 while( size>0 ){
460 if( size>(sizeof(zHex)-1)/2 ){
461 n = (sizeof(zHex)-1)/2;
462 }else{
463 n = size;
464 }
465 memcpy(zHex, zBin, n);
466 zBin += n;
467 size -= n;
468 sqlite3TestBinToHex(zHex, n);
469 Tcl_AppendResult(interp, zHex, (char*)0);
470 }
471 return TCL_OK;
472}
473
474/*
drh2f999a62007-08-15 19:16:43 +0000475** Usage: sqlite3_memory_used
476**
477** Raw test interface for sqlite3_memory_used().
478*/
479static int test_memory_used(
480 void * clientData,
481 Tcl_Interp *interp,
482 int objc,
483 Tcl_Obj *CONST objv[]
484){
485 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
486 return TCL_OK;
487}
488
489/*
490** Usage: sqlite3_memory_highwater ?RESETFLAG?
491**
492** Raw test interface for sqlite3_memory_highwater().
493*/
494static int test_memory_highwater(
495 void * clientData,
496 Tcl_Interp *interp,
497 int objc,
498 Tcl_Obj *CONST objv[]
499){
500 int resetFlag = 0;
501 if( objc!=1 && objc!=2 ){
502 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
503 return TCL_ERROR;
504 }
505 if( objc==2 ){
506 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
507 }
508 Tcl_SetObjResult(interp,
509 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
510 return TCL_OK;
511}
512
513/*
514** Usage: sqlite3_memdebug_backtrace DEPTH
515**
516** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
517** then this routine is a no-op.
518*/
519static int test_memdebug_backtrace(
520 void * clientData,
521 Tcl_Interp *interp,
522 int objc,
523 Tcl_Obj *CONST objv[]
524){
525 int depth;
526 if( objc!=2 ){
527 Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
528 return TCL_ERROR;
529 }
530 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
531#ifdef SQLITE_MEMDEBUG
532 {
drh49e4fd72008-02-19 15:15:15 +0000533 extern void sqlite3MemdebugBacktrace(int);
534 sqlite3MemdebugBacktrace(depth);
drh2f999a62007-08-15 19:16:43 +0000535 }
536#endif
537 return TCL_OK;
538}
539
540/*
541** Usage: sqlite3_memdebug_dump FILENAME
542**
543** Write a summary of unfreed memory to FILENAME.
544*/
545static int test_memdebug_dump(
546 void * clientData,
547 Tcl_Interp *interp,
548 int objc,
549 Tcl_Obj *CONST objv[]
550){
551 if( objc!=2 ){
552 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
553 return TCL_ERROR;
554 }
drh2d7636e2008-02-16 16:21:45 +0000555#if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
556 || defined(SQLITE_POW2_MEMORY_SIZE)
drh2f999a62007-08-15 19:16:43 +0000557 {
drh49e4fd72008-02-19 15:15:15 +0000558 extern void sqlite3MemdebugDump(const char*);
559 sqlite3MemdebugDump(Tcl_GetString(objv[1]));
drh2f999a62007-08-15 19:16:43 +0000560 }
561#endif
562 return TCL_OK;
563}
564
danielk1977a7a8e142008-02-13 18:25:27 +0000565/*
566** Usage: sqlite3_memdebug_malloc_count
567**
568** Return the total number of times malloc() has been called.
569*/
570static int test_memdebug_malloc_count(
571 void * clientData,
572 Tcl_Interp *interp,
573 int objc,
574 Tcl_Obj *CONST objv[]
575){
576 int nMalloc = -1;
577 if( objc!=1 ){
578 Tcl_WrongNumArgs(interp, 1, objv, "");
579 return TCL_ERROR;
580 }
581#if defined(SQLITE_MEMDEBUG)
582 {
drh49e4fd72008-02-19 15:15:15 +0000583 extern int sqlite3MemdebugMallocCount();
584 nMalloc = sqlite3MemdebugMallocCount();
danielk1977a7a8e142008-02-13 18:25:27 +0000585 }
586#endif
587 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
588 return TCL_OK;
589}
590
drh2f999a62007-08-15 19:16:43 +0000591
592/*
danielk1977a1644fd2007-08-29 12:31:25 +0000593** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
594**
595** where options are:
596**
drh643167f2008-01-22 21:30:53 +0000597** -repeat <count>
danielk1977a1644fd2007-08-29 12:31:25 +0000598** -benigncnt <varname>
drh0e6f1542007-08-15 20:41:28 +0000599**
600** Arrange for a simulated malloc() failure after COUNTER successes.
drh643167f2008-01-22 21:30:53 +0000601** If a repeat count is specified, the fault is repeated that many
602** times.
drh0e6f1542007-08-15 20:41:28 +0000603**
604** Each call to this routine overrides the prior counter value.
605** This routine returns the number of simulated failures that have
606** happened since the previous call to this routine.
607**
608** To disable simulated failures, use a COUNTER of -1.
609*/
610static int test_memdebug_fail(
611 void * clientData,
612 Tcl_Interp *interp,
613 int objc,
614 Tcl_Obj *CONST objv[]
615){
danielk1977a1644fd2007-08-29 12:31:25 +0000616 int ii;
drh0e6f1542007-08-15 20:41:28 +0000617 int iFail;
drh643167f2008-01-22 21:30:53 +0000618 int nRepeat = 1;
danielk1977a1644fd2007-08-29 12:31:25 +0000619 Tcl_Obj *pBenignCnt = 0;
drh643167f2008-01-22 21:30:53 +0000620 int nBenign;
drh0e6f1542007-08-15 20:41:28 +0000621 int nFail = 0;
danielk1977a1644fd2007-08-29 12:31:25 +0000622
623 if( objc<2 ){
624 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
drh0e6f1542007-08-15 20:41:28 +0000625 return TCL_ERROR;
626 }
627 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
danielk1977a1644fd2007-08-29 12:31:25 +0000628
629 for(ii=2; ii<objc; ii+=2){
630 int nOption;
631 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
632 char *zErr = 0;
633
634 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
635 if( ii==(objc-1) ){
636 zErr = "option requires an argument: ";
637 }else{
drh643167f2008-01-22 21:30:53 +0000638 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
danielk1977a1644fd2007-08-29 12:31:25 +0000639 return TCL_ERROR;
640 }
641 }
642 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
643 if( ii==(objc-1) ){
644 zErr = "option requires an argument: ";
645 }else{
646 pBenignCnt = objv[ii+1];
647 }
648 }else{
649 zErr = "unknown option: ";
650 }
651
652 if( zErr ){
653 Tcl_AppendResult(interp, zErr, zOption, 0);
654 return TCL_ERROR;
655 }
drhed138fb2007-08-22 22:04:37 +0000656 }
danielk1977a1644fd2007-08-29 12:31:25 +0000657
danielk1977ef05f2d2008-06-20 11:05:37 +0000658 nBenign = faultsimBenignFailures();
659 nFail = faultsimFailures();
660 faultsimConfig(iFail, nRepeat);
661
drh643167f2008-01-22 21:30:53 +0000662 if( pBenignCnt ){
663 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
drh0e6f1542007-08-15 20:41:28 +0000664 }
drh0e6f1542007-08-15 20:41:28 +0000665 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
666 return TCL_OK;
667}
668
danielk1977cd037242007-08-30 15:46:06 +0000669/*
670** Usage: sqlite3_memdebug_pending
671**
672** Return the number of malloc() calls that will succeed before a
673** simulated failure occurs. A negative return value indicates that
674** no malloc() failure is scheduled.
675*/
676static int test_memdebug_pending(
677 void * clientData,
678 Tcl_Interp *interp,
679 int objc,
680 Tcl_Obj *CONST objv[]
681){
drh5efaf072008-03-18 00:07:10 +0000682 int nPending;
danielk1977cd037242007-08-30 15:46:06 +0000683 if( objc!=1 ){
684 Tcl_WrongNumArgs(interp, 1, objv, "");
685 return TCL_ERROR;
686 }
danielk1977ef05f2d2008-06-20 11:05:37 +0000687 nPending = faultsimPending();
drh5efaf072008-03-18 00:07:10 +0000688 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
danielk1977cd037242007-08-30 15:46:06 +0000689 return TCL_OK;
690}
691
drh0e6f1542007-08-15 20:41:28 +0000692
693/*
drh4a50aac2007-08-23 02:47:53 +0000694** Usage: sqlite3_memdebug_settitle TITLE
695**
696** Set a title string stored with each allocation. The TITLE is
697** typically the name of the test that was running when the
698** allocation occurred. The TITLE is stored with the allocation
699** and can be used to figure out which tests are leaking memory.
700**
701** Each title overwrite the previous.
702*/
703static int test_memdebug_settitle(
704 void * clientData,
705 Tcl_Interp *interp,
706 int objc,
707 Tcl_Obj *CONST objv[]
708){
709 const char *zTitle;
710 if( objc!=2 ){
711 Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
712 return TCL_ERROR;
713 }
714 zTitle = Tcl_GetString(objv[1]);
715#ifdef SQLITE_MEMDEBUG
716 {
drh49e4fd72008-02-19 15:15:15 +0000717 extern int sqlite3MemdebugSettitle(const char*);
718 sqlite3MemdebugSettitle(zTitle);
drh4a50aac2007-08-23 02:47:53 +0000719 }
720#endif
721 return TCL_OK;
722}
723
danielk1977cd3e8f72008-03-25 09:47:35 +0000724#define MALLOC_LOG_FRAMES 10
danielk19776f332c12008-03-21 14:22:44 +0000725static Tcl_HashTable aMallocLog;
726static int mallocLogEnabled = 0;
727
728typedef struct MallocLog MallocLog;
729struct MallocLog {
730 int nCall;
731 int nByte;
732};
733
shaneafdd23a2008-05-29 02:57:47 +0000734#ifdef SQLITE_MEMDEBUG
danielk19776f332c12008-03-21 14:22:44 +0000735static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
736 if( mallocLogEnabled ){
737 MallocLog *pLog;
738 Tcl_HashEntry *pEntry;
739 int isNew;
740
741 int aKey[MALLOC_LOG_FRAMES];
742 int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
743
744 memset(aKey, 0, nKey);
745 if( (sizeof(void*)*nFrame)<nKey ){
746 nKey = nFrame*sizeof(void*);
747 }
748 memcpy(aKey, aFrame, nKey);
749
750 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
751 if( isNew ){
752 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
753 memset(pLog, 0, sizeof(MallocLog));
754 Tcl_SetHashValue(pEntry, (ClientData)pLog);
755 }else{
756 pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
757 }
758
759 pLog->nCall++;
760 pLog->nByte += nByte;
761 }
762}
shaneafdd23a2008-05-29 02:57:47 +0000763#endif /* SQLITE_MEMDEBUG */
danielk19776f332c12008-03-21 14:22:44 +0000764
danielk19775f096132008-03-28 15:44:09 +0000765static void test_memdebug_log_clear(){
danielk1977dbdc4d42008-03-28 07:42:53 +0000766 Tcl_HashSearch search;
767 Tcl_HashEntry *pEntry;
768 for(
769 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
770 pEntry;
771 pEntry=Tcl_NextHashEntry(&search)
772 ){
773 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
774 Tcl_Free((char *)pLog);
775 }
776 Tcl_DeleteHashTable(&aMallocLog);
777 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
778}
779
danielk19776f332c12008-03-21 14:22:44 +0000780static int test_memdebug_log(
781 void * clientData,
782 Tcl_Interp *interp,
783 int objc,
784 Tcl_Obj *CONST objv[]
785){
786 static int isInit = 0;
787 int iSub;
788
danielk1977dbdc4d42008-03-28 07:42:53 +0000789 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
790 enum MB_enum {
791 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
792 };
danielk19776f332c12008-03-21 14:22:44 +0000793
794 if( !isInit ){
795#ifdef SQLITE_MEMDEBUG
796 extern void sqlite3MemdebugBacktraceCallback(
797 void (*xBacktrace)(int, int, void **));
798 sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
799#endif
800 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
801 isInit = 1;
802 }
803
804 if( objc<2 ){
805 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
806 }
807 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
808 return TCL_ERROR;
809 }
810
811 switch( (enum MB_enum)iSub ){
812 case MB_LOG_START:
813 mallocLogEnabled = 1;
814 break;
815 case MB_LOG_STOP:
816 mallocLogEnabled = 0;
817 break;
818 case MB_LOG_DUMP: {
819 Tcl_HashSearch search;
820 Tcl_HashEntry *pEntry;
821 Tcl_Obj *pRet = Tcl_NewObj();
822
823 assert(sizeof(int)==sizeof(void*));
824
825 for(
826 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
827 pEntry;
828 pEntry=Tcl_NextHashEntry(&search)
829 ){
830 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
831 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
832 int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry);
833 int ii;
834
835 apElem[0] = Tcl_NewIntObj(pLog->nCall);
836 apElem[1] = Tcl_NewIntObj(pLog->nByte);
837 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
838 apElem[ii+2] = Tcl_NewIntObj(aKey[ii]);
839 }
840
841 Tcl_ListObjAppendElement(interp, pRet,
842 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
843 );
844 }
845
846 Tcl_SetObjResult(interp, pRet);
847 break;
848 }
849 case MB_LOG_CLEAR: {
danielk1977dbdc4d42008-03-28 07:42:53 +0000850 test_memdebug_log_clear();
851 break;
852 }
853
854 case MB_LOG_SYNC: {
drhb9404922008-03-28 12:53:38 +0000855#ifdef SQLITE_MEMDEBUG
danielk1977dbdc4d42008-03-28 07:42:53 +0000856 extern void sqlite3MemdebugSync();
857 test_memdebug_log_clear();
858 mallocLogEnabled = 1;
859 sqlite3MemdebugSync();
drhb9404922008-03-28 12:53:38 +0000860#endif
danielk1977dbdc4d42008-03-28 07:42:53 +0000861 break;
danielk19776f332c12008-03-21 14:22:44 +0000862 }
863 }
864
865 return TCL_OK;
866}
drh4a50aac2007-08-23 02:47:53 +0000867
868/*
drh9ac3fe92008-06-18 18:12:04 +0000869** Usage: sqlite3_config_scratch SIZE N
870**
871** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
872** The buffer is static and is of limited size. N might be
873** adjusted downward as needed to accomodate the requested size.
874** The revised value of N is returned.
875**
876** A negative SIZE causes the buffer pointer to be NULL.
877*/
878static int test_config_scratch(
879 void * clientData,
880 Tcl_Interp *interp,
881 int objc,
882 Tcl_Obj *CONST objv[]
883){
884 int sz, N, rc;
885 Tcl_Obj *pResult;
drh5f4bcf12008-07-29 14:29:06 +0000886 static char *buf = 0;
drh9ac3fe92008-06-18 18:12:04 +0000887 if( objc!=3 ){
888 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
889 return TCL_ERROR;
890 }
drhf7141992008-06-19 00:16:08 +0000891 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
892 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
drh5f4bcf12008-07-29 14:29:06 +0000893 free(buf);
drh9ac3fe92008-06-18 18:12:04 +0000894 if( sz<0 ){
drh5f4bcf12008-07-29 14:29:06 +0000895 buf = 0;
drh9ac3fe92008-06-18 18:12:04 +0000896 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
drhf7141992008-06-19 00:16:08 +0000897 }else{
drh6480aad2008-08-01 16:31:14 +0000898 buf = malloc( sz*N + 1 );
drh9ac3fe92008-06-18 18:12:04 +0000899 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
900 }
901 pResult = Tcl_NewObj();
902 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
903 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
904 Tcl_SetObjResult(interp, pResult);
905 return TCL_OK;
906}
907
908/*
909** Usage: sqlite3_config_pagecache SIZE N
910**
911** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
912** The buffer is static and is of limited size. N might be
913** adjusted downward as needed to accomodate the requested size.
914** The revised value of N is returned.
915**
916** A negative SIZE causes the buffer pointer to be NULL.
917*/
918static int test_config_pagecache(
919 void * clientData,
920 Tcl_Interp *interp,
921 int objc,
922 Tcl_Obj *CONST objv[]
923){
924 int sz, N, rc;
925 Tcl_Obj *pResult;
drh5f4bcf12008-07-29 14:29:06 +0000926 static char *buf = 0;
drh9ac3fe92008-06-18 18:12:04 +0000927 if( objc!=3 ){
928 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
929 return TCL_ERROR;
930 }
drhf7141992008-06-19 00:16:08 +0000931 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
932 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
drh5f4bcf12008-07-29 14:29:06 +0000933 free(buf);
drh9ac3fe92008-06-18 18:12:04 +0000934 if( sz<0 ){
drh5f4bcf12008-07-29 14:29:06 +0000935 buf = 0;
drhf7141992008-06-19 00:16:08 +0000936 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
937 }else{
drh0a60a382008-07-31 17:16:05 +0000938 buf = malloc( sz*N );
drh9ac3fe92008-06-18 18:12:04 +0000939 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
940 }
941 pResult = Tcl_NewObj();
942 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
943 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
944 Tcl_SetObjResult(interp, pResult);
945 return TCL_OK;
946}
947
drhf7141992008-06-19 00:16:08 +0000948/*
drhb232c232008-11-19 01:20:26 +0000949** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
950**
951** Set up the alternative test page cache. Install if INSTALL_FLAG is
952** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
953** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive
954** which determines the chance of discarding a page when unpinned. 100
955** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator
956** seed.
957*/
958static int test_alt_pcache(
959 void * clientData,
960 Tcl_Interp *interp,
961 int objc,
962 Tcl_Obj *CONST objv[]
963){
964 int installFlag;
drhf2a84e32009-01-07 03:59:47 +0000965 int discardChance = 0;
966 int prngSeed = 0;
967 int highStress = 0;
968 extern void installTestPCache(int,unsigned,unsigned,unsigned);
969 if( objc<2 || objc>5 ){
970 Tcl_WrongNumArgs(interp, 1, objv,
971 "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
drhb232c232008-11-19 01:20:26 +0000972 return TCL_ERROR;
973 }
974 if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
drhf2a84e32009-01-07 03:59:47 +0000975 if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){
976 return TCL_ERROR;
977 }
978 if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){
979 return TCL_ERROR;
980 }
981 if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){
982 return TCL_ERROR;
983 }
drhb232c232008-11-19 01:20:26 +0000984 if( discardChance<0 || discardChance>100 ){
985 Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
986 (char*)0);
987 return TCL_ERROR;
988 }
drhf2a84e32009-01-07 03:59:47 +0000989 installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,
990 (unsigned)highStress);
drhb232c232008-11-19 01:20:26 +0000991 return TCL_OK;
992}
993
994/*
drh8a42cbd2008-07-10 18:13:42 +0000995** Usage: sqlite3_config_memstatus BOOLEAN
996**
997** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
998*/
999static int test_config_memstatus(
1000 void * clientData,
1001 Tcl_Interp *interp,
1002 int objc,
1003 Tcl_Obj *CONST objv[]
1004){
1005 int enable, rc;
1006 if( objc!=2 ){
1007 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1008 return TCL_ERROR;
1009 }
1010 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
1011 rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
1012 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1013 return TCL_OK;
1014}
1015
1016/*
drh633e6d52008-07-28 19:34:53 +00001017** Usage: sqlite3_config_lookaside SIZE COUNT
1018**
1019*/
1020static int test_config_lookaside(
1021 void * clientData,
1022 Tcl_Interp *interp,
1023 int objc,
1024 Tcl_Obj *CONST objv[]
1025){
1026 int rc;
1027 int sz, cnt;
danielk1977ab7bee82008-10-15 11:43:55 +00001028 Tcl_Obj *pRet;
drh633e6d52008-07-28 19:34:53 +00001029 if( objc!=3 ){
1030 Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1031 return TCL_ERROR;
1032 }
1033 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1034 if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
danielk1977ab7bee82008-10-15 11:43:55 +00001035 pRet = Tcl_NewObj();
1036 Tcl_ListObjAppendElement(
1037 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)
1038 );
1039 Tcl_ListObjAppendElement(
1040 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)
1041 );
drh633e6d52008-07-28 19:34:53 +00001042 rc = sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
danielk1977ab7bee82008-10-15 11:43:55 +00001043 Tcl_SetObjResult(interp, pRet);
drh633e6d52008-07-28 19:34:53 +00001044 return TCL_OK;
1045}
1046
1047
1048/*
drhe9d1c722008-08-04 20:13:26 +00001049** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT
drh633e6d52008-07-28 19:34:53 +00001050**
drhe9d1c722008-08-04 20:13:26 +00001051** There are two static buffers with BUFID 1 and 2. Each static buffer
1052** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
1053** which will cause sqlite3_db_config() to allocate space on its own.
drh633e6d52008-07-28 19:34:53 +00001054*/
1055static int test_db_config_lookaside(
1056 void * clientData,
1057 Tcl_Interp *interp,
1058 int objc,
1059 Tcl_Obj *CONST objv[]
1060){
1061 int rc;
1062 int sz, cnt;
1063 sqlite3 *db;
drhe9d1c722008-08-04 20:13:26 +00001064 int bufid;
1065 static char azBuf[2][10000];
drh633e6d52008-07-28 19:34:53 +00001066 int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
drhe9d1c722008-08-04 20:13:26 +00001067 if( objc!=5 ){
1068 Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
drh633e6d52008-07-28 19:34:53 +00001069 return TCL_ERROR;
1070 }
1071 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
drhe9d1c722008-08-04 20:13:26 +00001072 if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
1073 if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
1074 if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
1075 if( bufid==0 ){
1076 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, sz, cnt);
1077 }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
1078 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
1079 }else{
1080 Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
1081 return TCL_ERROR;
1082 }
drh633e6d52008-07-28 19:34:53 +00001083 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1084 return TCL_OK;
1085}
1086
1087/*
danielk19775099be52008-06-27 13:27:03 +00001088** Usage:
1089**
drh8a42cbd2008-07-10 18:13:42 +00001090** sqlite3_config_heap NBYTE NMINALLOC
danielk19775099be52008-06-27 13:27:03 +00001091*/
1092static int test_config_heap(
1093 void * clientData,
1094 Tcl_Interp *interp,
1095 int objc,
1096 Tcl_Obj *CONST objv[]
1097){
drh7830cd42008-07-16 12:25:32 +00001098 static char *zBuf; /* Use this memory */
1099 static int szBuf; /* Bytes allocated for zBuf */
danielk19775099be52008-06-27 13:27:03 +00001100 int nByte; /* Size of buffer to pass to sqlite3_config() */
1101 int nMinAlloc; /* Size of minimum allocation */
1102 int rc; /* Return code of sqlite3_config() */
danielk19775099be52008-06-27 13:27:03 +00001103
1104 Tcl_Obj * CONST *aArg = &objv[1];
1105 int nArg = objc-1;
1106
danielk19775099be52008-06-27 13:27:03 +00001107 if( nArg!=2 ){
drh8a42cbd2008-07-10 18:13:42 +00001108 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
danielk19775099be52008-06-27 13:27:03 +00001109 return TCL_ERROR;
1110 }
1111 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1112 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
1113
danielk19770d84e5b2008-06-27 14:05:24 +00001114 if( nByte==0 ){
drh7830cd42008-07-16 12:25:32 +00001115 free( zBuf );
1116 zBuf = 0;
1117 szBuf = 0;
drh8a42cbd2008-07-10 18:13:42 +00001118 rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
danielk19770d84e5b2008-06-27 14:05:24 +00001119 }else{
drh7830cd42008-07-16 12:25:32 +00001120 zBuf = realloc(zBuf, nByte);
1121 szBuf = nByte;
danielk19770d84e5b2008-06-27 14:05:24 +00001122 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
danielk19775099be52008-06-27 13:27:03 +00001123 }
danielk19775099be52008-06-27 13:27:03 +00001124
1125 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1126 return TCL_OK;
1127}
1128
1129/*
drh6480aad2008-08-01 16:31:14 +00001130** tclcmd: sqlite3_config_error [DB]
1131**
1132** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1133** opcodes and verify that they return errors.
1134*/
1135static int test_config_error(
1136 void * clientData,
1137 Tcl_Interp *interp,
1138 int objc,
1139 Tcl_Obj *CONST objv[]
1140){
1141 sqlite3 *db;
1142 int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1143
1144 if( objc!=2 && objc!=1 ){
1145 Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
1146 return TCL_ERROR;
1147 }
1148 if( objc==2 ){
1149 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1150 if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
1151 Tcl_AppendResult(interp,
1152 "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
1153 (char*)0);
1154 return TCL_ERROR;
1155 }
1156 }else{
1157 if( sqlite3_config(99999)!=SQLITE_ERROR ){
1158 Tcl_AppendResult(interp,
1159 "sqlite3_config(99999) does not return SQLITE_ERROR",
1160 (char*)0);
1161 return TCL_ERROR;
1162 }
1163 }
1164 return TCL_OK;
1165}
1166
1167/*
danielk1977c66c0e12008-06-25 14:26:07 +00001168** Usage:
1169**
1170** sqlite3_dump_memsys3 FILENAME
1171** sqlite3_dump_memsys5 FILENAME
danielk197732155ef2008-06-25 10:34:34 +00001172**
1173** Write a summary of unfreed memsys3 allocations to FILENAME.
1174*/
1175static int test_dump_memsys3(
1176 void * clientData,
1177 Tcl_Interp *interp,
1178 int objc,
1179 Tcl_Obj *CONST objv[]
1180){
1181 if( objc!=2 ){
1182 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
1183 return TCL_ERROR;
1184 }
danielk1977c66c0e12008-06-25 14:26:07 +00001185
1186 switch( (int)clientData ){
danielk19770d84e5b2008-06-27 14:05:24 +00001187 case 3: {
danielk1977c66c0e12008-06-25 14:26:07 +00001188#ifdef SQLITE_ENABLE_MEMSYS3
1189 extern void sqlite3Memsys3Dump(const char*);
1190 sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1191 break;
danielk197732155ef2008-06-25 10:34:34 +00001192#endif
danielk1977c66c0e12008-06-25 14:26:07 +00001193 }
danielk19770d84e5b2008-06-27 14:05:24 +00001194 case 5: {
danielk1977c66c0e12008-06-25 14:26:07 +00001195#ifdef SQLITE_ENABLE_MEMSYS5
1196 extern void sqlite3Memsys5Dump(const char*);
1197 sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1198 break;
1199#endif
1200 }
1201 }
danielk197732155ef2008-06-25 10:34:34 +00001202 return TCL_OK;
1203}
1204
1205/*
drhf7141992008-06-19 00:16:08 +00001206** Usage: sqlite3_status OPCODE RESETFLAG
1207**
1208** Return a list of three elements which are the sqlite3_status() return
1209** code, the current value, and the high-water mark value.
1210*/
1211static int test_status(
1212 void * clientData,
1213 Tcl_Interp *interp,
1214 int objc,
1215 Tcl_Obj *CONST objv[]
1216){
1217 int rc, iValue, mxValue;
1218 int i, op, resetFlag;
1219 const char *zOpName;
1220 static const struct {
1221 const char *zName;
1222 int op;
1223 } aOp[] = {
1224 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED },
drhe50135e2008-08-05 17:53:22 +00001225 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },
drhf7141992008-06-19 00:16:08 +00001226 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED },
1227 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW },
drhe50135e2008-08-05 17:53:22 +00001228 { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE },
drhf7141992008-06-19 00:16:08 +00001229 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED },
1230 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },
drhe50135e2008-08-05 17:53:22 +00001231 { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE },
drhec424a52008-07-25 15:39:03 +00001232 { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK },
drhf7141992008-06-19 00:16:08 +00001233 };
1234 Tcl_Obj *pResult;
1235 if( objc!=3 ){
1236 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1237 return TCL_ERROR;
1238 }
1239 zOpName = Tcl_GetString(objv[1]);
1240 for(i=0; i<ArraySize(aOp); i++){
1241 if( strcmp(aOp[i].zName, zOpName)==0 ){
1242 op = aOp[i].op;
1243 break;
1244 }
1245 }
1246 if( i>=ArraySize(aOp) ){
1247 if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1248 }
1249 if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
drhaf005fb2008-07-09 16:51:51 +00001250 iValue = 0;
1251 mxValue = 0;
drhf7141992008-06-19 00:16:08 +00001252 rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1253 pResult = Tcl_NewObj();
1254 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1255 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1256 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1257 Tcl_SetObjResult(interp, pResult);
1258 return TCL_OK;
1259}
drh9ac3fe92008-06-18 18:12:04 +00001260
1261/*
drh633e6d52008-07-28 19:34:53 +00001262** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG
1263**
1264** Return a list of three elements which are the sqlite3_db_status() return
1265** code, the current value, and the high-water mark value.
1266*/
1267static int test_db_status(
1268 void * clientData,
1269 Tcl_Interp *interp,
1270 int objc,
1271 Tcl_Obj *CONST objv[]
1272){
1273 int rc, iValue, mxValue;
1274 int i, op, resetFlag;
1275 const char *zOpName;
1276 sqlite3 *db;
1277 int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1278 static const struct {
1279 const char *zName;
1280 int op;
1281 } aOp[] = {
1282 { "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
1283 };
1284 Tcl_Obj *pResult;
1285 if( objc!=4 ){
1286 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1287 return TCL_ERROR;
1288 }
1289 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1290 zOpName = Tcl_GetString(objv[2]);
1291 for(i=0; i<ArraySize(aOp); i++){
1292 if( strcmp(aOp[i].zName, zOpName)==0 ){
1293 op = aOp[i].op;
1294 break;
1295 }
1296 }
1297 if( i>=ArraySize(aOp) ){
1298 if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1299 }
1300 if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1301 iValue = 0;
1302 mxValue = 0;
1303 rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1304 pResult = Tcl_NewObj();
1305 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1306 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1307 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1308 Tcl_SetObjResult(interp, pResult);
1309 return TCL_OK;
1310}
1311
1312/*
danielk1977d09414c2008-06-19 18:17:49 +00001313** install_malloc_faultsim BOOLEAN
1314*/
1315static int test_install_malloc_faultsim(
1316 void * clientData,
1317 Tcl_Interp *interp,
1318 int objc,
1319 Tcl_Obj *CONST objv[]
1320){
1321 int rc;
1322 int isInstall;
1323
1324 if( objc!=2 ){
1325 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1326 return TCL_ERROR;
1327 }
1328 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1329 return TCL_ERROR;
1330 }
danielk1977ef05f2d2008-06-20 11:05:37 +00001331 rc = faultsimInstall(isInstall);
danielk1977d09414c2008-06-19 18:17:49 +00001332 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1333 return TCL_OK;
1334}
1335
1336/*
drh2f999a62007-08-15 19:16:43 +00001337** Register commands with the TCL interpreter.
1338*/
1339int Sqlitetest_malloc_Init(Tcl_Interp *interp){
1340 static struct {
1341 char *zName;
1342 Tcl_ObjCmdProc *xProc;
danielk1977c66c0e12008-06-25 14:26:07 +00001343 int clientData;
drh2f999a62007-08-15 19:16:43 +00001344 } aObjCmd[] = {
drh8a42cbd2008-07-10 18:13:42 +00001345 { "sqlite3_malloc", test_malloc ,0 },
1346 { "sqlite3_realloc", test_realloc ,0 },
1347 { "sqlite3_free", test_free ,0 },
1348 { "memset", test_memset ,0 },
1349 { "memget", test_memget ,0 },
1350 { "sqlite3_memory_used", test_memory_used ,0 },
1351 { "sqlite3_memory_highwater", test_memory_highwater ,0 },
1352 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 },
1353 { "sqlite3_memdebug_dump", test_memdebug_dump ,0 },
1354 { "sqlite3_memdebug_fail", test_memdebug_fail ,0 },
1355 { "sqlite3_memdebug_pending", test_memdebug_pending ,0 },
1356 { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 },
1357 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
1358 { "sqlite3_memdebug_log", test_memdebug_log ,0 },
1359 { "sqlite3_config_scratch", test_config_scratch ,0 },
1360 { "sqlite3_config_pagecache", test_config_pagecache ,0 },
drhb232c232008-11-19 01:20:26 +00001361 { "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
drh8a42cbd2008-07-10 18:13:42 +00001362 { "sqlite3_status", test_status ,0 },
drh633e6d52008-07-28 19:34:53 +00001363 { "sqlite3_db_status", test_db_status ,0 },
drh8a42cbd2008-07-10 18:13:42 +00001364 { "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
danielk19770d84e5b2008-06-27 14:05:24 +00001365 { "sqlite3_config_heap", test_config_heap ,0 },
drh8a42cbd2008-07-10 18:13:42 +00001366 { "sqlite3_config_memstatus", test_config_memstatus ,0 },
drh633e6d52008-07-28 19:34:53 +00001367 { "sqlite3_config_lookaside", test_config_lookaside ,0 },
drh6480aad2008-08-01 16:31:14 +00001368 { "sqlite3_config_error", test_config_error ,0 },
drh633e6d52008-07-28 19:34:53 +00001369 { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
danielk19770d84e5b2008-06-27 14:05:24 +00001370 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
drhb232c232008-11-19 01:20:26 +00001371 { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
drh2f999a62007-08-15 19:16:43 +00001372 };
1373 int i;
1374 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
danielk1977c66c0e12008-06-25 14:26:07 +00001375 ClientData c = (ClientData)aObjCmd[i].clientData;
1376 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
drh2f999a62007-08-15 19:16:43 +00001377 }
1378 return TCL_OK;
1379}
danielk1977ef05f2d2008-06-20 11:05:37 +00001380#endif