blob: 78bb281285cc01147d0367aca6f7c4f49719e2b5 [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**
danielk197764aca192009-04-07 11:21:28 +000016** $Id: test_malloc.c,v 1.54 2009/04/07 11:21:29 danielk1977 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*/
danielk197764aca192009-04-07 11:21:28 +000052static int faultsimStep(void){
danielk1977ef05f2d2008-06-20 11:05:37 +000053 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;
danielk1977b48c1f12009-02-04 15:27:40 +0000135
136 /* Sometimes, when running multi-threaded tests, the isBenignMode
137 ** variable is not properly incremented/decremented so that it is
138 ** 0 when not inside a benign malloc block. This doesn't affect
139 ** the multi-threaded tests, as they do not use this system. But
140 ** it does affect OOM tests run later in the same process. So
141 ** zero the variable here, just to be sure.
142 */
143 memfault.isBenignMode = 0;
danielk1977ef05f2d2008-06-20 11:05:37 +0000144}
145
146/*
147** Return the number of faults (both hard and benign faults) that have
148** occurred since the injector was last configured.
149*/
150static int faultsimFailures(void){
151 return memfault.nFail;
152}
153
154/*
155** Return the number of benign faults that have occurred since the
156** injector was last configured.
157*/
158static int faultsimBenignFailures(void){
159 return memfault.nBenign;
160}
161
162/*
163** Return the number of successes that will occur before the next failure.
164** If no failures are scheduled, return -1.
165*/
166static int faultsimPending(void){
167 if( memfault.enable ){
168 return memfault.iCountdown;
169 }else{
170 return -1;
171 }
172}
173
danielk19772d1d86f2008-06-20 14:59:51 +0000174
175static void faultsimBeginBenign(void){
176 memfault.isBenignMode++;
177}
178static void faultsimEndBenign(void){
179 memfault.isBenignMode--;
180}
181
danielk1977ef05f2d2008-06-20 11:05:37 +0000182/*
183** Add or remove the fault-simulation layer using sqlite3_config(). If
184** the argument is non-zero, the
185*/
186static int faultsimInstall(int install){
187 static struct sqlite3_mem_methods m = {
188 faultsimMalloc, /* xMalloc */
189 faultsimFree, /* xFree */
190 faultsimRealloc, /* xRealloc */
191 faultsimSize, /* xSize */
192 faultsimRoundup, /* xRoundup */
193 faultsimInit, /* xInit */
194 faultsimShutdown, /* xShutdown */
195 0 /* pAppData */
196 };
197 int rc;
198
199 install = (install ? 1 : 0);
200 assert(memfault.isInstalled==1 || memfault.isInstalled==0);
201
202 if( install==memfault.isInstalled ){
203 return SQLITE_ERROR;
204 }
205
danielk19772d1d86f2008-06-20 14:59:51 +0000206 if( install ){
207 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
208 assert(memfault.m.xMalloc);
209 if( rc==SQLITE_OK ){
210 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
211 }
212 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
213 faultsimBeginBenign, faultsimEndBenign
214 );
215 }else{
drh1b67f3c2008-10-10 17:41:28 +0000216 sqlite3_mem_methods m;
danielk19772d1d86f2008-06-20 14:59:51 +0000217 assert(memfault.m.xMalloc);
drh1b67f3c2008-10-10 17:41:28 +0000218
219 /* One should be able to reset the default memory allocator by storing
220 ** a zeroed allocator then calling GETMALLOC. */
221 memset(&m, 0, sizeof(m));
222 sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
223 sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m);
224 assert( memcmp(&m, &memfault.m, sizeof(m))==0 );
225
danielk19772d1d86f2008-06-20 14:59:51 +0000226 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
227 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0);
danielk1977ef05f2d2008-06-20 11:05:37 +0000228 }
229
230 if( rc==SQLITE_OK ){
231 memfault.isInstalled = 1;
232 }
233 return rc;
234}
235
236#ifdef SQLITE_TEST
237
238/*
239** This function is implemented in test1.c. Returns a pointer to a static
240** buffer containing the symbolic SQLite error code that corresponds to
241** the least-significant 8-bits of the integer passed as an argument.
242** For example:
243**
244** sqlite3TestErrorName(1) -> "SQLITE_ERROR"
245*/
danielk1977d09414c2008-06-19 18:17:49 +0000246const char *sqlite3TestErrorName(int);
247
drh2f999a62007-08-15 19:16:43 +0000248/*
249** Transform pointers to text and back again
250*/
251static void pointerToText(void *p, char *z){
252 static const char zHex[] = "0123456789abcdef";
253 int i, k;
drh4a50aac2007-08-23 02:47:53 +0000254 unsigned int u;
255 sqlite3_uint64 n;
drh8a42cbd2008-07-10 18:13:42 +0000256 if( p==0 ){
257 strcpy(z, "0");
258 return;
259 }
drh4a50aac2007-08-23 02:47:53 +0000260 if( sizeof(n)==sizeof(p) ){
261 memcpy(&n, &p, sizeof(p));
262 }else if( sizeof(u)==sizeof(p) ){
263 memcpy(&u, &p, sizeof(u));
264 n = u;
265 }else{
266 assert( 0 );
267 }
drh2f999a62007-08-15 19:16:43 +0000268 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
269 z[k] = zHex[n&0xf];
270 n >>= 4;
271 }
272 z[sizeof(p)*2] = 0;
273}
274static int hexToInt(int h){
275 if( h>='0' && h<='9' ){
276 return h - '0';
277 }else if( h>='a' && h<='f' ){
278 return h - 'a' + 10;
279 }else{
280 return -1;
281 }
282}
283static int textToPointer(const char *z, void **pp){
284 sqlite3_uint64 n = 0;
285 int i;
drh4a50aac2007-08-23 02:47:53 +0000286 unsigned int u;
drh2f999a62007-08-15 19:16:43 +0000287 for(i=0; i<sizeof(void*)*2 && z[0]; i++){
288 int v;
289 v = hexToInt(*z++);
290 if( v<0 ) return TCL_ERROR;
291 n = n*16 + v;
292 }
293 if( *z!=0 ) return TCL_ERROR;
drh4a50aac2007-08-23 02:47:53 +0000294 if( sizeof(n)==sizeof(*pp) ){
295 memcpy(pp, &n, sizeof(n));
296 }else if( sizeof(u)==sizeof(*pp) ){
297 u = (unsigned int)n;
298 memcpy(pp, &u, sizeof(u));
299 }else{
300 assert( 0 );
301 }
drh2f999a62007-08-15 19:16:43 +0000302 return TCL_OK;
303}
304
305/*
306** Usage: sqlite3_malloc NBYTES
307**
308** Raw test interface for sqlite3_malloc().
309*/
310static int test_malloc(
311 void * clientData,
312 Tcl_Interp *interp,
313 int objc,
314 Tcl_Obj *CONST objv[]
315){
316 int nByte;
317 void *p;
318 char zOut[100];
319 if( objc!=2 ){
320 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
321 return TCL_ERROR;
322 }
323 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
324 p = sqlite3_malloc((unsigned)nByte);
325 pointerToText(p, zOut);
326 Tcl_AppendResult(interp, zOut, NULL);
327 return TCL_OK;
328}
329
330/*
331** Usage: sqlite3_realloc PRIOR NBYTES
332**
333** Raw test interface for sqlite3_realloc().
334*/
335static int test_realloc(
336 void * clientData,
337 Tcl_Interp *interp,
338 int objc,
339 Tcl_Obj *CONST objv[]
340){
341 int nByte;
342 void *pPrior, *p;
343 char zOut[100];
344 if( objc!=3 ){
345 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
346 return TCL_ERROR;
347 }
348 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
349 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
350 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
351 return TCL_ERROR;
352 }
353 p = sqlite3_realloc(pPrior, (unsigned)nByte);
354 pointerToText(p, zOut);
355 Tcl_AppendResult(interp, zOut, NULL);
356 return TCL_OK;
357}
358
drh2f999a62007-08-15 19:16:43 +0000359/*
360** Usage: sqlite3_free PRIOR
361**
362** Raw test interface for sqlite3_free().
363*/
364static int test_free(
365 void * clientData,
366 Tcl_Interp *interp,
367 int objc,
368 Tcl_Obj *CONST objv[]
369){
370 void *pPrior;
371 if( objc!=2 ){
372 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
373 return TCL_ERROR;
374 }
375 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
376 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
377 return TCL_ERROR;
378 }
379 sqlite3_free(pPrior);
380 return TCL_OK;
381}
382
383/*
drh9c7a60d2007-10-19 17:47:24 +0000384** These routines are in test_hexio.c
385*/
386int sqlite3TestHexToBin(const char *, int, char *);
387int sqlite3TestBinToHex(char*,int);
388
389/*
390** Usage: memset ADDRESS SIZE HEX
391**
392** Set a chunk of memory (obtained from malloc, probably) to a
393** specified hex pattern.
394*/
395static int test_memset(
396 void * clientData,
397 Tcl_Interp *interp,
398 int objc,
399 Tcl_Obj *CONST objv[]
400){
401 void *p;
402 int size, n, i;
403 char *zHex;
404 char *zOut;
405 char zBin[100];
406
407 if( objc!=4 ){
408 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
409 return TCL_ERROR;
410 }
411 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
412 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
413 return TCL_ERROR;
414 }
415 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
416 return TCL_ERROR;
417 }
418 if( size<=0 ){
419 Tcl_AppendResult(interp, "size must be positive", (char*)0);
420 return TCL_ERROR;
421 }
422 zHex = Tcl_GetStringFromObj(objv[3], &n);
423 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
424 n = sqlite3TestHexToBin(zHex, n, zBin);
425 if( n==0 ){
426 Tcl_AppendResult(interp, "no data", (char*)0);
427 return TCL_ERROR;
428 }
429 zOut = p;
430 for(i=0; i<size; i++){
431 zOut[i] = zBin[i%n];
432 }
433 return TCL_OK;
434}
435
436/*
437** Usage: memget ADDRESS SIZE
438**
439** Return memory as hexadecimal text.
440*/
441static int test_memget(
442 void * clientData,
443 Tcl_Interp *interp,
444 int objc,
445 Tcl_Obj *CONST objv[]
446){
447 void *p;
448 int size, n;
449 char *zBin;
450 char zHex[100];
451
452 if( objc!=3 ){
453 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
454 return TCL_ERROR;
455 }
456 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
457 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
458 return TCL_ERROR;
459 }
460 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
461 return TCL_ERROR;
462 }
463 if( size<=0 ){
464 Tcl_AppendResult(interp, "size must be positive", (char*)0);
465 return TCL_ERROR;
466 }
467 zBin = p;
468 while( size>0 ){
469 if( size>(sizeof(zHex)-1)/2 ){
470 n = (sizeof(zHex)-1)/2;
471 }else{
472 n = size;
473 }
474 memcpy(zHex, zBin, n);
475 zBin += n;
476 size -= n;
477 sqlite3TestBinToHex(zHex, n);
478 Tcl_AppendResult(interp, zHex, (char*)0);
479 }
480 return TCL_OK;
481}
482
483/*
drh2f999a62007-08-15 19:16:43 +0000484** Usage: sqlite3_memory_used
485**
486** Raw test interface for sqlite3_memory_used().
487*/
488static int test_memory_used(
489 void * clientData,
490 Tcl_Interp *interp,
491 int objc,
492 Tcl_Obj *CONST objv[]
493){
494 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
495 return TCL_OK;
496}
497
498/*
499** Usage: sqlite3_memory_highwater ?RESETFLAG?
500**
501** Raw test interface for sqlite3_memory_highwater().
502*/
503static int test_memory_highwater(
504 void * clientData,
505 Tcl_Interp *interp,
506 int objc,
507 Tcl_Obj *CONST objv[]
508){
509 int resetFlag = 0;
510 if( objc!=1 && objc!=2 ){
511 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
512 return TCL_ERROR;
513 }
514 if( objc==2 ){
515 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
516 }
517 Tcl_SetObjResult(interp,
518 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
519 return TCL_OK;
520}
521
522/*
523** Usage: sqlite3_memdebug_backtrace DEPTH
524**
525** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
526** then this routine is a no-op.
527*/
528static int test_memdebug_backtrace(
529 void * clientData,
530 Tcl_Interp *interp,
531 int objc,
532 Tcl_Obj *CONST objv[]
533){
534 int depth;
535 if( objc!=2 ){
536 Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
537 return TCL_ERROR;
538 }
539 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
540#ifdef SQLITE_MEMDEBUG
541 {
drh49e4fd72008-02-19 15:15:15 +0000542 extern void sqlite3MemdebugBacktrace(int);
543 sqlite3MemdebugBacktrace(depth);
drh2f999a62007-08-15 19:16:43 +0000544 }
545#endif
546 return TCL_OK;
547}
548
549/*
550** Usage: sqlite3_memdebug_dump FILENAME
551**
552** Write a summary of unfreed memory to FILENAME.
553*/
554static int test_memdebug_dump(
555 void * clientData,
556 Tcl_Interp *interp,
557 int objc,
558 Tcl_Obj *CONST objv[]
559){
560 if( objc!=2 ){
561 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
562 return TCL_ERROR;
563 }
drh2d7636e2008-02-16 16:21:45 +0000564#if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
565 || defined(SQLITE_POW2_MEMORY_SIZE)
drh2f999a62007-08-15 19:16:43 +0000566 {
drh49e4fd72008-02-19 15:15:15 +0000567 extern void sqlite3MemdebugDump(const char*);
568 sqlite3MemdebugDump(Tcl_GetString(objv[1]));
drh2f999a62007-08-15 19:16:43 +0000569 }
570#endif
571 return TCL_OK;
572}
573
danielk1977a7a8e142008-02-13 18:25:27 +0000574/*
575** Usage: sqlite3_memdebug_malloc_count
576**
577** Return the total number of times malloc() has been called.
578*/
579static int test_memdebug_malloc_count(
580 void * clientData,
581 Tcl_Interp *interp,
582 int objc,
583 Tcl_Obj *CONST objv[]
584){
585 int nMalloc = -1;
586 if( objc!=1 ){
587 Tcl_WrongNumArgs(interp, 1, objv, "");
588 return TCL_ERROR;
589 }
590#if defined(SQLITE_MEMDEBUG)
591 {
drh49e4fd72008-02-19 15:15:15 +0000592 extern int sqlite3MemdebugMallocCount();
593 nMalloc = sqlite3MemdebugMallocCount();
danielk1977a7a8e142008-02-13 18:25:27 +0000594 }
595#endif
596 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
597 return TCL_OK;
598}
599
drh2f999a62007-08-15 19:16:43 +0000600
601/*
danielk1977a1644fd2007-08-29 12:31:25 +0000602** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
603**
604** where options are:
605**
drh643167f2008-01-22 21:30:53 +0000606** -repeat <count>
danielk1977a1644fd2007-08-29 12:31:25 +0000607** -benigncnt <varname>
drh0e6f1542007-08-15 20:41:28 +0000608**
609** Arrange for a simulated malloc() failure after COUNTER successes.
drh643167f2008-01-22 21:30:53 +0000610** If a repeat count is specified, the fault is repeated that many
611** times.
drh0e6f1542007-08-15 20:41:28 +0000612**
613** Each call to this routine overrides the prior counter value.
614** This routine returns the number of simulated failures that have
615** happened since the previous call to this routine.
616**
617** To disable simulated failures, use a COUNTER of -1.
618*/
619static int test_memdebug_fail(
620 void * clientData,
621 Tcl_Interp *interp,
622 int objc,
623 Tcl_Obj *CONST objv[]
624){
danielk1977a1644fd2007-08-29 12:31:25 +0000625 int ii;
drh0e6f1542007-08-15 20:41:28 +0000626 int iFail;
drh643167f2008-01-22 21:30:53 +0000627 int nRepeat = 1;
danielk1977a1644fd2007-08-29 12:31:25 +0000628 Tcl_Obj *pBenignCnt = 0;
drh643167f2008-01-22 21:30:53 +0000629 int nBenign;
drh0e6f1542007-08-15 20:41:28 +0000630 int nFail = 0;
danielk1977a1644fd2007-08-29 12:31:25 +0000631
632 if( objc<2 ){
633 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
drh0e6f1542007-08-15 20:41:28 +0000634 return TCL_ERROR;
635 }
636 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
danielk1977a1644fd2007-08-29 12:31:25 +0000637
638 for(ii=2; ii<objc; ii+=2){
639 int nOption;
640 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
641 char *zErr = 0;
642
643 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
644 if( ii==(objc-1) ){
645 zErr = "option requires an argument: ";
646 }else{
drh643167f2008-01-22 21:30:53 +0000647 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
danielk1977a1644fd2007-08-29 12:31:25 +0000648 return TCL_ERROR;
649 }
650 }
651 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
652 if( ii==(objc-1) ){
653 zErr = "option requires an argument: ";
654 }else{
655 pBenignCnt = objv[ii+1];
656 }
657 }else{
658 zErr = "unknown option: ";
659 }
660
661 if( zErr ){
662 Tcl_AppendResult(interp, zErr, zOption, 0);
663 return TCL_ERROR;
664 }
drhed138fb2007-08-22 22:04:37 +0000665 }
danielk1977a1644fd2007-08-29 12:31:25 +0000666
danielk1977ef05f2d2008-06-20 11:05:37 +0000667 nBenign = faultsimBenignFailures();
668 nFail = faultsimFailures();
669 faultsimConfig(iFail, nRepeat);
670
drh643167f2008-01-22 21:30:53 +0000671 if( pBenignCnt ){
672 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
drh0e6f1542007-08-15 20:41:28 +0000673 }
drh0e6f1542007-08-15 20:41:28 +0000674 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
675 return TCL_OK;
676}
677
danielk1977cd037242007-08-30 15:46:06 +0000678/*
679** Usage: sqlite3_memdebug_pending
680**
681** Return the number of malloc() calls that will succeed before a
682** simulated failure occurs. A negative return value indicates that
683** no malloc() failure is scheduled.
684*/
685static int test_memdebug_pending(
686 void * clientData,
687 Tcl_Interp *interp,
688 int objc,
689 Tcl_Obj *CONST objv[]
690){
drh5efaf072008-03-18 00:07:10 +0000691 int nPending;
danielk1977cd037242007-08-30 15:46:06 +0000692 if( objc!=1 ){
693 Tcl_WrongNumArgs(interp, 1, objv, "");
694 return TCL_ERROR;
695 }
danielk1977ef05f2d2008-06-20 11:05:37 +0000696 nPending = faultsimPending();
drh5efaf072008-03-18 00:07:10 +0000697 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
danielk1977cd037242007-08-30 15:46:06 +0000698 return TCL_OK;
699}
700
drh0e6f1542007-08-15 20:41:28 +0000701
702/*
drh4a50aac2007-08-23 02:47:53 +0000703** Usage: sqlite3_memdebug_settitle TITLE
704**
705** Set a title string stored with each allocation. The TITLE is
706** typically the name of the test that was running when the
707** allocation occurred. The TITLE is stored with the allocation
708** and can be used to figure out which tests are leaking memory.
709**
710** Each title overwrite the previous.
711*/
712static int test_memdebug_settitle(
713 void * clientData,
714 Tcl_Interp *interp,
715 int objc,
716 Tcl_Obj *CONST objv[]
717){
718 const char *zTitle;
719 if( objc!=2 ){
720 Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
721 return TCL_ERROR;
722 }
723 zTitle = Tcl_GetString(objv[1]);
724#ifdef SQLITE_MEMDEBUG
725 {
drh49e4fd72008-02-19 15:15:15 +0000726 extern int sqlite3MemdebugSettitle(const char*);
727 sqlite3MemdebugSettitle(zTitle);
drh4a50aac2007-08-23 02:47:53 +0000728 }
729#endif
730 return TCL_OK;
731}
732
danielk1977cd3e8f72008-03-25 09:47:35 +0000733#define MALLOC_LOG_FRAMES 10
danielk19776f332c12008-03-21 14:22:44 +0000734static Tcl_HashTable aMallocLog;
735static int mallocLogEnabled = 0;
736
737typedef struct MallocLog MallocLog;
738struct MallocLog {
739 int nCall;
740 int nByte;
741};
742
shaneafdd23a2008-05-29 02:57:47 +0000743#ifdef SQLITE_MEMDEBUG
danielk19776f332c12008-03-21 14:22:44 +0000744static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
745 if( mallocLogEnabled ){
746 MallocLog *pLog;
747 Tcl_HashEntry *pEntry;
748 int isNew;
749
750 int aKey[MALLOC_LOG_FRAMES];
751 int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
752
753 memset(aKey, 0, nKey);
754 if( (sizeof(void*)*nFrame)<nKey ){
755 nKey = nFrame*sizeof(void*);
756 }
757 memcpy(aKey, aFrame, nKey);
758
759 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
760 if( isNew ){
761 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
762 memset(pLog, 0, sizeof(MallocLog));
763 Tcl_SetHashValue(pEntry, (ClientData)pLog);
764 }else{
765 pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
766 }
767
768 pLog->nCall++;
769 pLog->nByte += nByte;
770 }
771}
shaneafdd23a2008-05-29 02:57:47 +0000772#endif /* SQLITE_MEMDEBUG */
danielk19776f332c12008-03-21 14:22:44 +0000773
danielk197764aca192009-04-07 11:21:28 +0000774static void test_memdebug_log_clear(void){
danielk1977dbdc4d42008-03-28 07:42:53 +0000775 Tcl_HashSearch search;
776 Tcl_HashEntry *pEntry;
777 for(
778 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
779 pEntry;
780 pEntry=Tcl_NextHashEntry(&search)
781 ){
782 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
783 Tcl_Free((char *)pLog);
784 }
785 Tcl_DeleteHashTable(&aMallocLog);
786 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
787}
788
danielk19776f332c12008-03-21 14:22:44 +0000789static int test_memdebug_log(
790 void * clientData,
791 Tcl_Interp *interp,
792 int objc,
793 Tcl_Obj *CONST objv[]
794){
795 static int isInit = 0;
796 int iSub;
797
danielk1977dbdc4d42008-03-28 07:42:53 +0000798 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
799 enum MB_enum {
800 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
801 };
danielk19776f332c12008-03-21 14:22:44 +0000802
803 if( !isInit ){
804#ifdef SQLITE_MEMDEBUG
805 extern void sqlite3MemdebugBacktraceCallback(
806 void (*xBacktrace)(int, int, void **));
807 sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
808#endif
809 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
810 isInit = 1;
811 }
812
813 if( objc<2 ){
814 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
815 }
816 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
817 return TCL_ERROR;
818 }
819
820 switch( (enum MB_enum)iSub ){
821 case MB_LOG_START:
822 mallocLogEnabled = 1;
823 break;
824 case MB_LOG_STOP:
825 mallocLogEnabled = 0;
826 break;
827 case MB_LOG_DUMP: {
828 Tcl_HashSearch search;
829 Tcl_HashEntry *pEntry;
830 Tcl_Obj *pRet = Tcl_NewObj();
831
832 assert(sizeof(int)==sizeof(void*));
833
834 for(
835 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
836 pEntry;
837 pEntry=Tcl_NextHashEntry(&search)
838 ){
839 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
840 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
841 int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry);
842 int ii;
843
844 apElem[0] = Tcl_NewIntObj(pLog->nCall);
845 apElem[1] = Tcl_NewIntObj(pLog->nByte);
846 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
847 apElem[ii+2] = Tcl_NewIntObj(aKey[ii]);
848 }
849
850 Tcl_ListObjAppendElement(interp, pRet,
851 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
852 );
853 }
854
855 Tcl_SetObjResult(interp, pRet);
856 break;
857 }
858 case MB_LOG_CLEAR: {
danielk1977dbdc4d42008-03-28 07:42:53 +0000859 test_memdebug_log_clear();
860 break;
861 }
862
863 case MB_LOG_SYNC: {
drhb9404922008-03-28 12:53:38 +0000864#ifdef SQLITE_MEMDEBUG
danielk1977dbdc4d42008-03-28 07:42:53 +0000865 extern void sqlite3MemdebugSync();
866 test_memdebug_log_clear();
867 mallocLogEnabled = 1;
868 sqlite3MemdebugSync();
drhb9404922008-03-28 12:53:38 +0000869#endif
danielk1977dbdc4d42008-03-28 07:42:53 +0000870 break;
danielk19776f332c12008-03-21 14:22:44 +0000871 }
872 }
873
874 return TCL_OK;
875}
drh4a50aac2007-08-23 02:47:53 +0000876
877/*
drh9ac3fe92008-06-18 18:12:04 +0000878** Usage: sqlite3_config_scratch SIZE N
879**
880** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
881** The buffer is static and is of limited size. N might be
882** adjusted downward as needed to accomodate the requested size.
883** The revised value of N is returned.
884**
885** A negative SIZE causes the buffer pointer to be NULL.
886*/
887static int test_config_scratch(
888 void * clientData,
889 Tcl_Interp *interp,
890 int objc,
891 Tcl_Obj *CONST objv[]
892){
893 int sz, N, rc;
894 Tcl_Obj *pResult;
drh5f4bcf12008-07-29 14:29:06 +0000895 static char *buf = 0;
drh9ac3fe92008-06-18 18:12:04 +0000896 if( objc!=3 ){
897 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
898 return TCL_ERROR;
899 }
drhf7141992008-06-19 00:16:08 +0000900 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
901 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
drh5f4bcf12008-07-29 14:29:06 +0000902 free(buf);
drh9ac3fe92008-06-18 18:12:04 +0000903 if( sz<0 ){
drh5f4bcf12008-07-29 14:29:06 +0000904 buf = 0;
drh9ac3fe92008-06-18 18:12:04 +0000905 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
drhf7141992008-06-19 00:16:08 +0000906 }else{
drh6480aad2008-08-01 16:31:14 +0000907 buf = malloc( sz*N + 1 );
drh9ac3fe92008-06-18 18:12:04 +0000908 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
909 }
910 pResult = Tcl_NewObj();
911 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
912 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
913 Tcl_SetObjResult(interp, pResult);
914 return TCL_OK;
915}
916
917/*
918** Usage: sqlite3_config_pagecache SIZE N
919**
920** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
921** The buffer is static and is of limited size. N might be
922** adjusted downward as needed to accomodate the requested size.
923** The revised value of N is returned.
924**
925** A negative SIZE causes the buffer pointer to be NULL.
926*/
927static int test_config_pagecache(
928 void * clientData,
929 Tcl_Interp *interp,
930 int objc,
931 Tcl_Obj *CONST objv[]
932){
933 int sz, N, rc;
934 Tcl_Obj *pResult;
drh5f4bcf12008-07-29 14:29:06 +0000935 static char *buf = 0;
drh9ac3fe92008-06-18 18:12:04 +0000936 if( objc!=3 ){
937 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
938 return TCL_ERROR;
939 }
drhf7141992008-06-19 00:16:08 +0000940 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
941 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
drh5f4bcf12008-07-29 14:29:06 +0000942 free(buf);
drh9ac3fe92008-06-18 18:12:04 +0000943 if( sz<0 ){
drh5f4bcf12008-07-29 14:29:06 +0000944 buf = 0;
drhf7141992008-06-19 00:16:08 +0000945 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
946 }else{
drh0a60a382008-07-31 17:16:05 +0000947 buf = malloc( sz*N );
drh9ac3fe92008-06-18 18:12:04 +0000948 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
949 }
950 pResult = Tcl_NewObj();
951 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
952 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
953 Tcl_SetObjResult(interp, pResult);
954 return TCL_OK;
955}
956
drhf7141992008-06-19 00:16:08 +0000957/*
drhb232c232008-11-19 01:20:26 +0000958** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
959**
960** Set up the alternative test page cache. Install if INSTALL_FLAG is
961** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
962** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive
963** which determines the chance of discarding a page when unpinned. 100
964** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator
965** seed.
966*/
967static int test_alt_pcache(
968 void * clientData,
969 Tcl_Interp *interp,
970 int objc,
971 Tcl_Obj *CONST objv[]
972){
973 int installFlag;
drhf2a84e32009-01-07 03:59:47 +0000974 int discardChance = 0;
975 int prngSeed = 0;
976 int highStress = 0;
977 extern void installTestPCache(int,unsigned,unsigned,unsigned);
978 if( objc<2 || objc>5 ){
979 Tcl_WrongNumArgs(interp, 1, objv,
980 "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
drhb232c232008-11-19 01:20:26 +0000981 return TCL_ERROR;
982 }
983 if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
drhf2a84e32009-01-07 03:59:47 +0000984 if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){
985 return TCL_ERROR;
986 }
987 if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){
988 return TCL_ERROR;
989 }
990 if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){
991 return TCL_ERROR;
992 }
drhb232c232008-11-19 01:20:26 +0000993 if( discardChance<0 || discardChance>100 ){
994 Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
995 (char*)0);
996 return TCL_ERROR;
997 }
drhf2a84e32009-01-07 03:59:47 +0000998 installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,
999 (unsigned)highStress);
drhb232c232008-11-19 01:20:26 +00001000 return TCL_OK;
1001}
1002
1003/*
drh8a42cbd2008-07-10 18:13:42 +00001004** Usage: sqlite3_config_memstatus BOOLEAN
1005**
1006** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
1007*/
1008static int test_config_memstatus(
1009 void * clientData,
1010 Tcl_Interp *interp,
1011 int objc,
1012 Tcl_Obj *CONST objv[]
1013){
1014 int enable, rc;
1015 if( objc!=2 ){
1016 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1017 return TCL_ERROR;
1018 }
1019 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
1020 rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
1021 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1022 return TCL_OK;
1023}
1024
1025/*
drh633e6d52008-07-28 19:34:53 +00001026** Usage: sqlite3_config_lookaside SIZE COUNT
1027**
1028*/
1029static int test_config_lookaside(
1030 void * clientData,
1031 Tcl_Interp *interp,
1032 int objc,
1033 Tcl_Obj *CONST objv[]
1034){
1035 int rc;
1036 int sz, cnt;
danielk1977ab7bee82008-10-15 11:43:55 +00001037 Tcl_Obj *pRet;
drh633e6d52008-07-28 19:34:53 +00001038 if( objc!=3 ){
1039 Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1040 return TCL_ERROR;
1041 }
1042 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1043 if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
danielk1977ab7bee82008-10-15 11:43:55 +00001044 pRet = Tcl_NewObj();
1045 Tcl_ListObjAppendElement(
1046 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)
1047 );
1048 Tcl_ListObjAppendElement(
1049 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)
1050 );
drh633e6d52008-07-28 19:34:53 +00001051 rc = sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
danielk1977ab7bee82008-10-15 11:43:55 +00001052 Tcl_SetObjResult(interp, pRet);
drh633e6d52008-07-28 19:34:53 +00001053 return TCL_OK;
1054}
1055
1056
1057/*
drhe9d1c722008-08-04 20:13:26 +00001058** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT
drh633e6d52008-07-28 19:34:53 +00001059**
drhe9d1c722008-08-04 20:13:26 +00001060** There are two static buffers with BUFID 1 and 2. Each static buffer
1061** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
1062** which will cause sqlite3_db_config() to allocate space on its own.
drh633e6d52008-07-28 19:34:53 +00001063*/
1064static int test_db_config_lookaside(
1065 void * clientData,
1066 Tcl_Interp *interp,
1067 int objc,
1068 Tcl_Obj *CONST objv[]
1069){
1070 int rc;
1071 int sz, cnt;
1072 sqlite3 *db;
drhe9d1c722008-08-04 20:13:26 +00001073 int bufid;
1074 static char azBuf[2][10000];
drh633e6d52008-07-28 19:34:53 +00001075 int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
drhe9d1c722008-08-04 20:13:26 +00001076 if( objc!=5 ){
1077 Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
drh633e6d52008-07-28 19:34:53 +00001078 return TCL_ERROR;
1079 }
1080 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
drhe9d1c722008-08-04 20:13:26 +00001081 if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
1082 if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
1083 if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
1084 if( bufid==0 ){
1085 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, sz, cnt);
1086 }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
1087 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
1088 }else{
1089 Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
1090 return TCL_ERROR;
1091 }
drh633e6d52008-07-28 19:34:53 +00001092 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1093 return TCL_OK;
1094}
1095
1096/*
danielk19775099be52008-06-27 13:27:03 +00001097** Usage:
1098**
drh8a42cbd2008-07-10 18:13:42 +00001099** sqlite3_config_heap NBYTE NMINALLOC
danielk19775099be52008-06-27 13:27:03 +00001100*/
1101static int test_config_heap(
1102 void * clientData,
1103 Tcl_Interp *interp,
1104 int objc,
1105 Tcl_Obj *CONST objv[]
1106){
drh7830cd42008-07-16 12:25:32 +00001107 static char *zBuf; /* Use this memory */
1108 static int szBuf; /* Bytes allocated for zBuf */
danielk19775099be52008-06-27 13:27:03 +00001109 int nByte; /* Size of buffer to pass to sqlite3_config() */
1110 int nMinAlloc; /* Size of minimum allocation */
1111 int rc; /* Return code of sqlite3_config() */
danielk19775099be52008-06-27 13:27:03 +00001112
1113 Tcl_Obj * CONST *aArg = &objv[1];
1114 int nArg = objc-1;
1115
danielk19775099be52008-06-27 13:27:03 +00001116 if( nArg!=2 ){
drh8a42cbd2008-07-10 18:13:42 +00001117 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
danielk19775099be52008-06-27 13:27:03 +00001118 return TCL_ERROR;
1119 }
1120 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1121 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
1122
danielk19770d84e5b2008-06-27 14:05:24 +00001123 if( nByte==0 ){
drh7830cd42008-07-16 12:25:32 +00001124 free( zBuf );
1125 zBuf = 0;
1126 szBuf = 0;
drh8a42cbd2008-07-10 18:13:42 +00001127 rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
danielk19770d84e5b2008-06-27 14:05:24 +00001128 }else{
drh7830cd42008-07-16 12:25:32 +00001129 zBuf = realloc(zBuf, nByte);
1130 szBuf = nByte;
danielk19770d84e5b2008-06-27 14:05:24 +00001131 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
danielk19775099be52008-06-27 13:27:03 +00001132 }
danielk19775099be52008-06-27 13:27:03 +00001133
1134 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1135 return TCL_OK;
1136}
1137
1138/*
drh6480aad2008-08-01 16:31:14 +00001139** tclcmd: sqlite3_config_error [DB]
1140**
1141** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1142** opcodes and verify that they return errors.
1143*/
1144static int test_config_error(
1145 void * clientData,
1146 Tcl_Interp *interp,
1147 int objc,
1148 Tcl_Obj *CONST objv[]
1149){
1150 sqlite3 *db;
1151 int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1152
1153 if( objc!=2 && objc!=1 ){
1154 Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
1155 return TCL_ERROR;
1156 }
1157 if( objc==2 ){
1158 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1159 if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
1160 Tcl_AppendResult(interp,
1161 "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
1162 (char*)0);
1163 return TCL_ERROR;
1164 }
1165 }else{
1166 if( sqlite3_config(99999)!=SQLITE_ERROR ){
1167 Tcl_AppendResult(interp,
1168 "sqlite3_config(99999) does not return SQLITE_ERROR",
1169 (char*)0);
1170 return TCL_ERROR;
1171 }
1172 }
1173 return TCL_OK;
1174}
1175
1176/*
danielk1977c66c0e12008-06-25 14:26:07 +00001177** Usage:
1178**
1179** sqlite3_dump_memsys3 FILENAME
1180** sqlite3_dump_memsys5 FILENAME
danielk197732155ef2008-06-25 10:34:34 +00001181**
1182** Write a summary of unfreed memsys3 allocations to FILENAME.
1183*/
1184static int test_dump_memsys3(
1185 void * clientData,
1186 Tcl_Interp *interp,
1187 int objc,
1188 Tcl_Obj *CONST objv[]
1189){
1190 if( objc!=2 ){
1191 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
1192 return TCL_ERROR;
1193 }
danielk1977c66c0e12008-06-25 14:26:07 +00001194
1195 switch( (int)clientData ){
danielk19770d84e5b2008-06-27 14:05:24 +00001196 case 3: {
danielk1977c66c0e12008-06-25 14:26:07 +00001197#ifdef SQLITE_ENABLE_MEMSYS3
1198 extern void sqlite3Memsys3Dump(const char*);
1199 sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1200 break;
danielk197732155ef2008-06-25 10:34:34 +00001201#endif
danielk1977c66c0e12008-06-25 14:26:07 +00001202 }
danielk19770d84e5b2008-06-27 14:05:24 +00001203 case 5: {
danielk1977c66c0e12008-06-25 14:26:07 +00001204#ifdef SQLITE_ENABLE_MEMSYS5
1205 extern void sqlite3Memsys5Dump(const char*);
1206 sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1207 break;
1208#endif
1209 }
1210 }
danielk197732155ef2008-06-25 10:34:34 +00001211 return TCL_OK;
1212}
1213
1214/*
drhf7141992008-06-19 00:16:08 +00001215** Usage: sqlite3_status OPCODE RESETFLAG
1216**
1217** Return a list of three elements which are the sqlite3_status() return
1218** code, the current value, and the high-water mark value.
1219*/
1220static int test_status(
1221 void * clientData,
1222 Tcl_Interp *interp,
1223 int objc,
1224 Tcl_Obj *CONST objv[]
1225){
1226 int rc, iValue, mxValue;
1227 int i, op, resetFlag;
1228 const char *zOpName;
1229 static const struct {
1230 const char *zName;
1231 int op;
1232 } aOp[] = {
1233 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED },
drhe50135e2008-08-05 17:53:22 +00001234 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },
drhf7141992008-06-19 00:16:08 +00001235 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED },
1236 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW },
drhe50135e2008-08-05 17:53:22 +00001237 { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE },
drhf7141992008-06-19 00:16:08 +00001238 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED },
1239 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },
drhe50135e2008-08-05 17:53:22 +00001240 { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE },
drhec424a52008-07-25 15:39:03 +00001241 { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK },
drhf7141992008-06-19 00:16:08 +00001242 };
1243 Tcl_Obj *pResult;
1244 if( objc!=3 ){
1245 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1246 return TCL_ERROR;
1247 }
1248 zOpName = Tcl_GetString(objv[1]);
1249 for(i=0; i<ArraySize(aOp); i++){
1250 if( strcmp(aOp[i].zName, zOpName)==0 ){
1251 op = aOp[i].op;
1252 break;
1253 }
1254 }
1255 if( i>=ArraySize(aOp) ){
1256 if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1257 }
1258 if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
drhaf005fb2008-07-09 16:51:51 +00001259 iValue = 0;
1260 mxValue = 0;
drhf7141992008-06-19 00:16:08 +00001261 rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1262 pResult = Tcl_NewObj();
1263 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1264 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1265 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1266 Tcl_SetObjResult(interp, pResult);
1267 return TCL_OK;
1268}
drh9ac3fe92008-06-18 18:12:04 +00001269
1270/*
drh633e6d52008-07-28 19:34:53 +00001271** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG
1272**
1273** Return a list of three elements which are the sqlite3_db_status() return
1274** code, the current value, and the high-water mark value.
1275*/
1276static int test_db_status(
1277 void * clientData,
1278 Tcl_Interp *interp,
1279 int objc,
1280 Tcl_Obj *CONST objv[]
1281){
1282 int rc, iValue, mxValue;
1283 int i, op, resetFlag;
1284 const char *zOpName;
1285 sqlite3 *db;
1286 int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1287 static const struct {
1288 const char *zName;
1289 int op;
1290 } aOp[] = {
1291 { "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
1292 };
1293 Tcl_Obj *pResult;
1294 if( objc!=4 ){
1295 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1296 return TCL_ERROR;
1297 }
1298 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1299 zOpName = Tcl_GetString(objv[2]);
1300 for(i=0; i<ArraySize(aOp); i++){
1301 if( strcmp(aOp[i].zName, zOpName)==0 ){
1302 op = aOp[i].op;
1303 break;
1304 }
1305 }
1306 if( i>=ArraySize(aOp) ){
1307 if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1308 }
1309 if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1310 iValue = 0;
1311 mxValue = 0;
1312 rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1313 pResult = Tcl_NewObj();
1314 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1315 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1316 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1317 Tcl_SetObjResult(interp, pResult);
1318 return TCL_OK;
1319}
1320
1321/*
danielk1977d09414c2008-06-19 18:17:49 +00001322** install_malloc_faultsim BOOLEAN
1323*/
1324static int test_install_malloc_faultsim(
1325 void * clientData,
1326 Tcl_Interp *interp,
1327 int objc,
1328 Tcl_Obj *CONST objv[]
1329){
1330 int rc;
1331 int isInstall;
1332
1333 if( objc!=2 ){
1334 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1335 return TCL_ERROR;
1336 }
1337 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1338 return TCL_ERROR;
1339 }
danielk1977ef05f2d2008-06-20 11:05:37 +00001340 rc = faultsimInstall(isInstall);
danielk1977d09414c2008-06-19 18:17:49 +00001341 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1342 return TCL_OK;
1343}
1344
1345/*
drh2f999a62007-08-15 19:16:43 +00001346** Register commands with the TCL interpreter.
1347*/
1348int Sqlitetest_malloc_Init(Tcl_Interp *interp){
1349 static struct {
1350 char *zName;
1351 Tcl_ObjCmdProc *xProc;
danielk1977c66c0e12008-06-25 14:26:07 +00001352 int clientData;
drh2f999a62007-08-15 19:16:43 +00001353 } aObjCmd[] = {
drh8a42cbd2008-07-10 18:13:42 +00001354 { "sqlite3_malloc", test_malloc ,0 },
1355 { "sqlite3_realloc", test_realloc ,0 },
1356 { "sqlite3_free", test_free ,0 },
1357 { "memset", test_memset ,0 },
1358 { "memget", test_memget ,0 },
1359 { "sqlite3_memory_used", test_memory_used ,0 },
1360 { "sqlite3_memory_highwater", test_memory_highwater ,0 },
1361 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 },
1362 { "sqlite3_memdebug_dump", test_memdebug_dump ,0 },
1363 { "sqlite3_memdebug_fail", test_memdebug_fail ,0 },
1364 { "sqlite3_memdebug_pending", test_memdebug_pending ,0 },
1365 { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 },
1366 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
1367 { "sqlite3_memdebug_log", test_memdebug_log ,0 },
1368 { "sqlite3_config_scratch", test_config_scratch ,0 },
1369 { "sqlite3_config_pagecache", test_config_pagecache ,0 },
drhb232c232008-11-19 01:20:26 +00001370 { "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
drh8a42cbd2008-07-10 18:13:42 +00001371 { "sqlite3_status", test_status ,0 },
drh633e6d52008-07-28 19:34:53 +00001372 { "sqlite3_db_status", test_db_status ,0 },
drh8a42cbd2008-07-10 18:13:42 +00001373 { "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
danielk19770d84e5b2008-06-27 14:05:24 +00001374 { "sqlite3_config_heap", test_config_heap ,0 },
drh8a42cbd2008-07-10 18:13:42 +00001375 { "sqlite3_config_memstatus", test_config_memstatus ,0 },
drh633e6d52008-07-28 19:34:53 +00001376 { "sqlite3_config_lookaside", test_config_lookaside ,0 },
drh6480aad2008-08-01 16:31:14 +00001377 { "sqlite3_config_error", test_config_error ,0 },
drh633e6d52008-07-28 19:34:53 +00001378 { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
danielk19770d84e5b2008-06-27 14:05:24 +00001379 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
drhb232c232008-11-19 01:20:26 +00001380 { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
drh2f999a62007-08-15 19:16:43 +00001381 };
1382 int i;
1383 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
danielk1977c66c0e12008-06-25 14:26:07 +00001384 ClientData c = (ClientData)aObjCmd[i].clientData;
1385 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
drh2f999a62007-08-15 19:16:43 +00001386 }
1387 return TCL_OK;
1388}
danielk1977ef05f2d2008-06-20 11:05:37 +00001389#endif