|
1 /* |
|
2 ** 2007 August 15 |
|
3 ** |
|
4 ** Portions Copyright (c) 2008 Nokia Corporation and/or its subsidiaries. All rights reserved. |
|
5 ** |
|
6 ** The author disclaims copyright to this source code. In place of |
|
7 ** a legal notice, here is a blessing: |
|
8 ** |
|
9 ** May you do good and not evil. |
|
10 ** May you find forgiveness for yourself and forgive others. |
|
11 ** May you share freely, never taking more than you give. |
|
12 ** |
|
13 ************************************************************************* |
|
14 ** |
|
15 ** This file contains code used to implement test interfaces to the |
|
16 ** memory allocation subsystem. |
|
17 ** |
|
18 ** $Id: test_malloc.c,v 1.47 2008/08/05 17:53:24 drh Exp $ |
|
19 */ |
|
20 #include "sqliteInt.h" |
|
21 #include "tcl.h" |
|
22 #include <stdlib.h> |
|
23 #include <string.h> |
|
24 #include <assert.h> |
|
25 #include <sys/param.h> |
|
26 |
|
27 /* Symbian OS */ |
|
28 extern char* GetFullFilePath(char* aPath, const char* aFileName); |
|
29 |
|
30 /* |
|
31 ** This structure is used to encapsulate the global state variables used |
|
32 ** by malloc() fault simulation. |
|
33 */ |
|
34 static struct MemFault { |
|
35 int iCountdown; /* Number of pending successes before a failure */ |
|
36 int nRepeat; /* Number of times to repeat the failure */ |
|
37 int nBenign; /* Number of benign failures seen since last config */ |
|
38 int nFail; /* Number of failures seen since last config */ |
|
39 u8 enable; /* True if enabled */ |
|
40 int isInstalled; /* True if the fault simulation layer is installed */ |
|
41 int isBenignMode; /* True if malloc failures are considered benign */ |
|
42 sqlite3_mem_methods m; /* 'Real' malloc implementation */ |
|
43 } memfault; |
|
44 |
|
45 /* |
|
46 ** This routine exists as a place to set a breakpoint that will |
|
47 ** fire on any simulated malloc() failure. |
|
48 */ |
|
49 static void sqlite3Fault(void){ |
|
50 static int cnt = 0; |
|
51 cnt++; |
|
52 } |
|
53 |
|
54 /* |
|
55 ** Check to see if a fault should be simulated. Return true to simulate |
|
56 ** the fault. Return false if the fault should not be simulated. |
|
57 */ |
|
58 static int faultsimStep(){ |
|
59 if( likely(!memfault.enable) ){ |
|
60 return 0; |
|
61 } |
|
62 if( memfault.iCountdown>0 ){ |
|
63 memfault.iCountdown--; |
|
64 return 0; |
|
65 } |
|
66 sqlite3Fault(); |
|
67 memfault.nFail++; |
|
68 if( memfault.isBenignMode>0 ){ |
|
69 memfault.nBenign++; |
|
70 } |
|
71 memfault.nRepeat--; |
|
72 if( memfault.nRepeat<=0 ){ |
|
73 memfault.enable = 0; |
|
74 } |
|
75 return 1; |
|
76 } |
|
77 |
|
78 |
|
79 /* |
|
80 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation |
|
81 ** logic. |
|
82 */ |
|
83 static void *faultsimMalloc(int n){ |
|
84 void *p = 0; |
|
85 if( !faultsimStep() ){ |
|
86 p = memfault.m.xMalloc(n); |
|
87 } |
|
88 return p; |
|
89 } |
|
90 |
|
91 |
|
92 /* |
|
93 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation |
|
94 ** logic. |
|
95 */ |
|
96 static void *faultsimRealloc(void *pOld, int n){ |
|
97 void *p = 0; |
|
98 if( !faultsimStep() ){ |
|
99 p = memfault.m.xRealloc(pOld, n); |
|
100 } |
|
101 return p; |
|
102 } |
|
103 |
|
104 /* |
|
105 ** The following method calls are passed directly through to the underlying |
|
106 ** malloc system: |
|
107 ** |
|
108 ** xFree |
|
109 ** xSize |
|
110 ** xRoundup |
|
111 ** xInit |
|
112 ** xShutdown |
|
113 */ |
|
114 static void faultsimFree(void *p){ |
|
115 memfault.m.xFree(p); |
|
116 } |
|
117 static int faultsimSize(void *p){ |
|
118 return memfault.m.xSize(p); |
|
119 } |
|
120 static int faultsimRoundup(int n){ |
|
121 return memfault.m.xRoundup(n); |
|
122 } |
|
123 static int faultsimInit(void *p){ |
|
124 return memfault.m.xInit(memfault.m.pAppData); |
|
125 } |
|
126 static void faultsimShutdown(void *p){ |
|
127 memfault.m.xShutdown(memfault.m.pAppData); |
|
128 } |
|
129 |
|
130 /* |
|
131 ** This routine configures the malloc failure simulation. After |
|
132 ** calling this routine, the next nDelay mallocs will succeed, followed |
|
133 ** by a block of nRepeat failures, after which malloc() calls will begin |
|
134 ** to succeed again. |
|
135 */ |
|
136 static void faultsimConfig(int nDelay, int nRepeat){ |
|
137 memfault.iCountdown = nDelay; |
|
138 memfault.nRepeat = nRepeat; |
|
139 memfault.nBenign = 0; |
|
140 memfault.nFail = 0; |
|
141 memfault.enable = nDelay>=0; |
|
142 } |
|
143 |
|
144 /* |
|
145 ** Return the number of faults (both hard and benign faults) that have |
|
146 ** occurred since the injector was last configured. |
|
147 */ |
|
148 static int faultsimFailures(void){ |
|
149 return memfault.nFail; |
|
150 } |
|
151 |
|
152 /* |
|
153 ** Return the number of benign faults that have occurred since the |
|
154 ** injector was last configured. |
|
155 */ |
|
156 static int faultsimBenignFailures(void){ |
|
157 return memfault.nBenign; |
|
158 } |
|
159 |
|
160 /* |
|
161 ** Return the number of successes that will occur before the next failure. |
|
162 ** If no failures are scheduled, return -1. |
|
163 */ |
|
164 static int faultsimPending(void){ |
|
165 if( memfault.enable ){ |
|
166 return memfault.iCountdown; |
|
167 }else{ |
|
168 return -1; |
|
169 } |
|
170 } |
|
171 |
|
172 |
|
173 static void faultsimBeginBenign(void){ |
|
174 memfault.isBenignMode++; |
|
175 } |
|
176 static void faultsimEndBenign(void){ |
|
177 memfault.isBenignMode--; |
|
178 } |
|
179 |
|
180 /* |
|
181 ** Add or remove the fault-simulation layer using sqlite3_config(). If |
|
182 ** the argument is non-zero, the |
|
183 */ |
|
184 static int faultsimInstall(int install){ |
|
185 static struct sqlite3_mem_methods m = { |
|
186 faultsimMalloc, /* xMalloc */ |
|
187 faultsimFree, /* xFree */ |
|
188 faultsimRealloc, /* xRealloc */ |
|
189 faultsimSize, /* xSize */ |
|
190 faultsimRoundup, /* xRoundup */ |
|
191 faultsimInit, /* xInit */ |
|
192 faultsimShutdown, /* xShutdown */ |
|
193 0 /* pAppData */ |
|
194 }; |
|
195 int rc; |
|
196 |
|
197 install = (install ? 1 : 0); |
|
198 assert(memfault.isInstalled==1 || memfault.isInstalled==0); |
|
199 |
|
200 if( install==memfault.isInstalled ){ |
|
201 return SQLITE_ERROR; |
|
202 } |
|
203 |
|
204 if( install ){ |
|
205 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m); |
|
206 assert(memfault.m.xMalloc); |
|
207 if( rc==SQLITE_OK ){ |
|
208 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m); |
|
209 } |
|
210 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, |
|
211 faultsimBeginBenign, faultsimEndBenign |
|
212 ); |
|
213 }else{ |
|
214 assert(memfault.m.xMalloc); |
|
215 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m); |
|
216 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0); |
|
217 } |
|
218 |
|
219 if( rc==SQLITE_OK ){ |
|
220 memfault.isInstalled = 1; |
|
221 } |
|
222 return rc; |
|
223 } |
|
224 |
|
225 #ifdef SQLITE_TEST |
|
226 |
|
227 /* |
|
228 ** This function is implemented in test1.c. Returns a pointer to a static |
|
229 ** buffer containing the symbolic SQLite error code that corresponds to |
|
230 ** the least-significant 8-bits of the integer passed as an argument. |
|
231 ** For example: |
|
232 ** |
|
233 ** sqlite3TestErrorName(1) -> "SQLITE_ERROR" |
|
234 */ |
|
235 const char *sqlite3TestErrorName(int); |
|
236 |
|
237 /* |
|
238 ** Transform pointers to text and back again |
|
239 */ |
|
240 static void pointerToText(void *p, char *z){ |
|
241 static const char zHex[] = "0123456789abcdef"; |
|
242 int i, k; |
|
243 unsigned int u; |
|
244 sqlite3_uint64 n; |
|
245 if( p==0 ){ |
|
246 strcpy(z, "0"); |
|
247 return; |
|
248 } |
|
249 if( sizeof(n)==sizeof(p) ){ |
|
250 memcpy(&n, &p, sizeof(p)); |
|
251 }else if( sizeof(u)==sizeof(p) ){ |
|
252 memcpy(&u, &p, sizeof(u)); |
|
253 n = u; |
|
254 }else{ |
|
255 assert( 0 ); |
|
256 } |
|
257 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){ |
|
258 z[k] = zHex[n&0xf]; |
|
259 n >>= 4; |
|
260 } |
|
261 z[sizeof(p)*2] = 0; |
|
262 } |
|
263 static int hexToInt(int h){ |
|
264 if( h>='0' && h<='9' ){ |
|
265 return h - '0'; |
|
266 }else if( h>='a' && h<='f' ){ |
|
267 return h - 'a' + 10; |
|
268 }else{ |
|
269 return -1; |
|
270 } |
|
271 } |
|
272 static int textToPointer(const char *z, void **pp){ |
|
273 sqlite3_uint64 n = 0; |
|
274 int i; |
|
275 unsigned int u; |
|
276 for(i=0; i<sizeof(void*)*2 && z[0]; i++){ |
|
277 int v; |
|
278 v = hexToInt(*z++); |
|
279 if( v<0 ) return TCL_ERROR; |
|
280 n = n*16 + v; |
|
281 } |
|
282 if( *z!=0 ) return TCL_ERROR; |
|
283 if( sizeof(n)==sizeof(*pp) ){ |
|
284 memcpy(pp, &n, sizeof(n)); |
|
285 }else if( sizeof(u)==sizeof(*pp) ){ |
|
286 u = (unsigned int)n; |
|
287 memcpy(pp, &u, sizeof(u)); |
|
288 }else{ |
|
289 assert( 0 ); |
|
290 } |
|
291 return TCL_OK; |
|
292 } |
|
293 |
|
294 /* |
|
295 ** Usage: sqlite3_malloc NBYTES |
|
296 ** |
|
297 ** Raw test interface for sqlite3_malloc(). |
|
298 */ |
|
299 static int test_malloc( |
|
300 void * clientData, |
|
301 Tcl_Interp *interp, |
|
302 int objc, |
|
303 Tcl_Obj *CONST objv[] |
|
304 ){ |
|
305 int nByte; |
|
306 void *p; |
|
307 char zOut[100]; |
|
308 if( objc!=2 ){ |
|
309 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES"); |
|
310 return TCL_ERROR; |
|
311 } |
|
312 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR; |
|
313 p = sqlite3_malloc((unsigned)nByte); |
|
314 pointerToText(p, zOut); |
|
315 Tcl_AppendResult(interp, zOut, NULL); |
|
316 return TCL_OK; |
|
317 } |
|
318 |
|
319 /* |
|
320 ** Usage: sqlite3_realloc PRIOR NBYTES |
|
321 ** |
|
322 ** Raw test interface for sqlite3_realloc(). |
|
323 */ |
|
324 static int test_realloc( |
|
325 void * clientData, |
|
326 Tcl_Interp *interp, |
|
327 int objc, |
|
328 Tcl_Obj *CONST objv[] |
|
329 ){ |
|
330 int nByte; |
|
331 void *pPrior, *p; |
|
332 char zOut[100]; |
|
333 if( objc!=3 ){ |
|
334 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES"); |
|
335 return TCL_ERROR; |
|
336 } |
|
337 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR; |
|
338 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ |
|
339 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); |
|
340 return TCL_ERROR; |
|
341 } |
|
342 p = sqlite3_realloc(pPrior, (unsigned)nByte); |
|
343 pointerToText(p, zOut); |
|
344 Tcl_AppendResult(interp, zOut, NULL); |
|
345 return TCL_OK; |
|
346 } |
|
347 |
|
348 /* |
|
349 ** Usage: sqlite3_free PRIOR |
|
350 ** |
|
351 ** Raw test interface for sqlite3_free(). |
|
352 */ |
|
353 static int test_free( |
|
354 void * clientData, |
|
355 Tcl_Interp *interp, |
|
356 int objc, |
|
357 Tcl_Obj *CONST objv[] |
|
358 ){ |
|
359 void *pPrior; |
|
360 if( objc!=2 ){ |
|
361 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR"); |
|
362 return TCL_ERROR; |
|
363 } |
|
364 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ |
|
365 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); |
|
366 return TCL_ERROR; |
|
367 } |
|
368 sqlite3_free(pPrior); |
|
369 return TCL_OK; |
|
370 } |
|
371 |
|
372 /* |
|
373 ** These routines are in test_hexio.c |
|
374 */ |
|
375 int sqlite3TestHexToBin(const char *, int, char *); |
|
376 int sqlite3TestBinToHex(char*,int); |
|
377 |
|
378 /* |
|
379 ** Usage: memset ADDRESS SIZE HEX |
|
380 ** |
|
381 ** Set a chunk of memory (obtained from malloc, probably) to a |
|
382 ** specified hex pattern. |
|
383 */ |
|
384 static int test_memset( |
|
385 void * clientData, |
|
386 Tcl_Interp *interp, |
|
387 int objc, |
|
388 Tcl_Obj *CONST objv[] |
|
389 ){ |
|
390 void *p; |
|
391 int size, n, i; |
|
392 char *zHex; |
|
393 char *zOut; |
|
394 char zBin[100]; |
|
395 |
|
396 if( objc!=4 ){ |
|
397 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX"); |
|
398 return TCL_ERROR; |
|
399 } |
|
400 if( textToPointer(Tcl_GetString(objv[1]), &p) ){ |
|
401 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); |
|
402 return TCL_ERROR; |
|
403 } |
|
404 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ |
|
405 return TCL_ERROR; |
|
406 } |
|
407 if( size<=0 ){ |
|
408 Tcl_AppendResult(interp, "size must be positive", (char*)0); |
|
409 return TCL_ERROR; |
|
410 } |
|
411 zHex = Tcl_GetStringFromObj(objv[3], &n); |
|
412 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2; |
|
413 n = sqlite3TestHexToBin(zHex, n, zBin); |
|
414 if( n==0 ){ |
|
415 Tcl_AppendResult(interp, "no data", (char*)0); |
|
416 return TCL_ERROR; |
|
417 } |
|
418 zOut = p; |
|
419 for(i=0; i<size; i++){ |
|
420 zOut[i] = zBin[i%n]; |
|
421 } |
|
422 return TCL_OK; |
|
423 } |
|
424 |
|
425 /* |
|
426 ** Usage: memget ADDRESS SIZE |
|
427 ** |
|
428 ** Return memory as hexadecimal text. |
|
429 */ |
|
430 static int test_memget( |
|
431 void * clientData, |
|
432 Tcl_Interp *interp, |
|
433 int objc, |
|
434 Tcl_Obj *CONST objv[] |
|
435 ){ |
|
436 void *p; |
|
437 int size, n; |
|
438 char *zBin; |
|
439 char zHex[100]; |
|
440 |
|
441 if( objc!=3 ){ |
|
442 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE"); |
|
443 return TCL_ERROR; |
|
444 } |
|
445 if( textToPointer(Tcl_GetString(objv[1]), &p) ){ |
|
446 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); |
|
447 return TCL_ERROR; |
|
448 } |
|
449 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ |
|
450 return TCL_ERROR; |
|
451 } |
|
452 if( size<=0 ){ |
|
453 Tcl_AppendResult(interp, "size must be positive", (char*)0); |
|
454 return TCL_ERROR; |
|
455 } |
|
456 zBin = p; |
|
457 while( size>0 ){ |
|
458 if( size>(sizeof(zHex)-1)/2 ){ |
|
459 n = (sizeof(zHex)-1)/2; |
|
460 }else{ |
|
461 n = size; |
|
462 } |
|
463 memcpy(zHex, zBin, n); |
|
464 zBin += n; |
|
465 size -= n; |
|
466 sqlite3TestBinToHex(zHex, n); |
|
467 Tcl_AppendResult(interp, zHex, (char*)0); |
|
468 } |
|
469 return TCL_OK; |
|
470 } |
|
471 |
|
472 /* |
|
473 ** Usage: sqlite3_memory_used |
|
474 ** |
|
475 ** Raw test interface for sqlite3_memory_used(). |
|
476 */ |
|
477 static int test_memory_used( |
|
478 void * clientData, |
|
479 Tcl_Interp *interp, |
|
480 int objc, |
|
481 Tcl_Obj *CONST objv[] |
|
482 ){ |
|
483 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used())); |
|
484 return TCL_OK; |
|
485 } |
|
486 |
|
487 /* |
|
488 ** Usage: sqlite3_memory_highwater ?RESETFLAG? |
|
489 ** |
|
490 ** Raw test interface for sqlite3_memory_highwater(). |
|
491 */ |
|
492 static int test_memory_highwater( |
|
493 void * clientData, |
|
494 Tcl_Interp *interp, |
|
495 int objc, |
|
496 Tcl_Obj *CONST objv[] |
|
497 ){ |
|
498 int resetFlag = 0; |
|
499 if( objc!=1 && objc!=2 ){ |
|
500 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?"); |
|
501 return TCL_ERROR; |
|
502 } |
|
503 if( objc==2 ){ |
|
504 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR; |
|
505 } |
|
506 Tcl_SetObjResult(interp, |
|
507 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag))); |
|
508 return TCL_OK; |
|
509 } |
|
510 |
|
511 /* |
|
512 ** Usage: sqlite3_memdebug_backtrace DEPTH |
|
513 ** |
|
514 ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined |
|
515 ** then this routine is a no-op. |
|
516 */ |
|
517 static int test_memdebug_backtrace( |
|
518 void * clientData, |
|
519 Tcl_Interp *interp, |
|
520 int objc, |
|
521 Tcl_Obj *CONST objv[] |
|
522 ){ |
|
523 int depth; |
|
524 if( objc!=2 ){ |
|
525 Tcl_WrongNumArgs(interp, 1, objv, "DEPT"); |
|
526 return TCL_ERROR; |
|
527 } |
|
528 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR; |
|
529 #ifdef SQLITE_MEMDEBUG |
|
530 { |
|
531 extern void sqlite3MemdebugBacktrace(int); |
|
532 sqlite3MemdebugBacktrace(depth); |
|
533 } |
|
534 #endif |
|
535 return TCL_OK; |
|
536 } |
|
537 |
|
538 /* |
|
539 ** Usage: sqlite3_memdebug_dump FILENAME |
|
540 ** |
|
541 ** Write a summary of unfreed memory to FILENAME. |
|
542 */ |
|
543 static int test_memdebug_dump( |
|
544 void * clientData, |
|
545 Tcl_Interp *interp, |
|
546 int objc, |
|
547 Tcl_Obj *CONST objv[] |
|
548 ){ |
|
549 char fnamebuf[MAXPATHLEN + 1]; |
|
550 if( objc!=2 ){ |
|
551 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); |
|
552 return TCL_ERROR; |
|
553 } |
|
554 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \ |
|
555 || defined(SQLITE_POW2_MEMORY_SIZE) |
|
556 { |
|
557 extern void sqlite3MemdebugDump(const char*); |
|
558 if(GetFullFilePath(fnamebuf, Tcl_GetString(objv[1])) == 0) |
|
559 return TCL_ERROR; |
|
560 sqlite3MemdebugDump(fnamebuf); |
|
561 } |
|
562 #endif |
|
563 return TCL_OK; |
|
564 } |
|
565 |
|
566 /* |
|
567 ** Usage: sqlite3_memdebug_malloc_count |
|
568 ** |
|
569 ** Return the total number of times malloc() has been called. |
|
570 */ |
|
571 static int test_memdebug_malloc_count( |
|
572 void * clientData, |
|
573 Tcl_Interp *interp, |
|
574 int objc, |
|
575 Tcl_Obj *CONST objv[] |
|
576 ){ |
|
577 int nMalloc = -1; |
|
578 if( objc!=1 ){ |
|
579 Tcl_WrongNumArgs(interp, 1, objv, ""); |
|
580 return TCL_ERROR; |
|
581 } |
|
582 #if defined(SQLITE_MEMDEBUG) |
|
583 { |
|
584 extern int sqlite3MemdebugMallocCount(); |
|
585 nMalloc = sqlite3MemdebugMallocCount(); |
|
586 } |
|
587 #endif |
|
588 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc)); |
|
589 return TCL_OK; |
|
590 } |
|
591 |
|
592 |
|
593 /* |
|
594 ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS? |
|
595 ** |
|
596 ** where options are: |
|
597 ** |
|
598 ** -repeat <count> |
|
599 ** -benigncnt <varname> |
|
600 ** |
|
601 ** Arrange for a simulated malloc() failure after COUNTER successes. |
|
602 ** If a repeat count is specified, the fault is repeated that many |
|
603 ** times. |
|
604 ** |
|
605 ** Each call to this routine overrides the prior counter value. |
|
606 ** This routine returns the number of simulated failures that have |
|
607 ** happened since the previous call to this routine. |
|
608 ** |
|
609 ** To disable simulated failures, use a COUNTER of -1. |
|
610 */ |
|
611 static int test_memdebug_fail( |
|
612 void * clientData, |
|
613 Tcl_Interp *interp, |
|
614 int objc, |
|
615 Tcl_Obj *CONST objv[] |
|
616 ){ |
|
617 int ii; |
|
618 int iFail; |
|
619 int nRepeat = 1; |
|
620 Tcl_Obj *pBenignCnt = 0; |
|
621 int nBenign; |
|
622 int nFail = 0; |
|
623 |
|
624 if( objc<2 ){ |
|
625 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?"); |
|
626 return TCL_ERROR; |
|
627 } |
|
628 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR; |
|
629 |
|
630 for(ii=2; ii<objc; ii+=2){ |
|
631 int nOption; |
|
632 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption); |
|
633 char *zErr = 0; |
|
634 |
|
635 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){ |
|
636 if( ii==(objc-1) ){ |
|
637 zErr = "option requires an argument: "; |
|
638 }else{ |
|
639 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){ |
|
640 return TCL_ERROR; |
|
641 } |
|
642 } |
|
643 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){ |
|
644 if( ii==(objc-1) ){ |
|
645 zErr = "option requires an argument: "; |
|
646 }else{ |
|
647 pBenignCnt = objv[ii+1]; |
|
648 } |
|
649 }else{ |
|
650 zErr = "unknown option: "; |
|
651 } |
|
652 |
|
653 if( zErr ){ |
|
654 Tcl_AppendResult(interp, zErr, zOption, 0); |
|
655 return TCL_ERROR; |
|
656 } |
|
657 } |
|
658 |
|
659 nBenign = faultsimBenignFailures(); |
|
660 nFail = faultsimFailures(); |
|
661 faultsimConfig(iFail, nRepeat); |
|
662 |
|
663 if( pBenignCnt ){ |
|
664 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0); |
|
665 } |
|
666 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail)); |
|
667 return TCL_OK; |
|
668 } |
|
669 |
|
670 /* |
|
671 ** Usage: sqlite3_memdebug_pending |
|
672 ** |
|
673 ** Return the number of malloc() calls that will succeed before a |
|
674 ** simulated failure occurs. A negative return value indicates that |
|
675 ** no malloc() failure is scheduled. |
|
676 */ |
|
677 static int test_memdebug_pending( |
|
678 void * clientData, |
|
679 Tcl_Interp *interp, |
|
680 int objc, |
|
681 Tcl_Obj *CONST objv[] |
|
682 ){ |
|
683 int nPending; |
|
684 if( objc!=1 ){ |
|
685 Tcl_WrongNumArgs(interp, 1, objv, ""); |
|
686 return TCL_ERROR; |
|
687 } |
|
688 nPending = faultsimPending(); |
|
689 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending)); |
|
690 return TCL_OK; |
|
691 } |
|
692 |
|
693 |
|
694 /* |
|
695 ** Usage: sqlite3_memdebug_settitle TITLE |
|
696 ** |
|
697 ** Set a title string stored with each allocation. The TITLE is |
|
698 ** typically the name of the test that was running when the |
|
699 ** allocation occurred. The TITLE is stored with the allocation |
|
700 ** and can be used to figure out which tests are leaking memory. |
|
701 ** |
|
702 ** Each title overwrite the previous. |
|
703 */ |
|
704 static int test_memdebug_settitle( |
|
705 void * clientData, |
|
706 Tcl_Interp *interp, |
|
707 int objc, |
|
708 Tcl_Obj *CONST objv[] |
|
709 ){ |
|
710 const char *zTitle; |
|
711 if( objc!=2 ){ |
|
712 Tcl_WrongNumArgs(interp, 1, objv, "TITLE"); |
|
713 return TCL_ERROR; |
|
714 } |
|
715 zTitle = Tcl_GetString(objv[1]); |
|
716 #ifdef SQLITE_MEMDEBUG |
|
717 { |
|
718 extern int sqlite3MemdebugSettitle(const char*); |
|
719 sqlite3MemdebugSettitle(zTitle); |
|
720 } |
|
721 #endif |
|
722 return TCL_OK; |
|
723 } |
|
724 |
|
725 #define MALLOC_LOG_FRAMES 10 |
|
726 static Tcl_HashTable aMallocLog; |
|
727 static int mallocLogEnabled = 0; |
|
728 |
|
729 typedef struct MallocLog MallocLog; |
|
730 struct MallocLog { |
|
731 int nCall; |
|
732 int nByte; |
|
733 }; |
|
734 |
|
735 #ifdef SQLITE_MEMDEBUG |
|
736 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){ |
|
737 if( mallocLogEnabled ){ |
|
738 MallocLog *pLog; |
|
739 Tcl_HashEntry *pEntry; |
|
740 int isNew; |
|
741 |
|
742 int aKey[MALLOC_LOG_FRAMES]; |
|
743 int nKey = sizeof(int)*MALLOC_LOG_FRAMES; |
|
744 |
|
745 memset(aKey, 0, nKey); |
|
746 if( (sizeof(void*)*nFrame)<nKey ){ |
|
747 nKey = nFrame*sizeof(void*); |
|
748 } |
|
749 memcpy(aKey, aFrame, nKey); |
|
750 |
|
751 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew); |
|
752 if( isNew ){ |
|
753 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog)); |
|
754 memset(pLog, 0, sizeof(MallocLog)); |
|
755 Tcl_SetHashValue(pEntry, (ClientData)pLog); |
|
756 }else{ |
|
757 pLog = (MallocLog *)Tcl_GetHashValue(pEntry); |
|
758 } |
|
759 |
|
760 pLog->nCall++; |
|
761 pLog->nByte += nByte; |
|
762 } |
|
763 } |
|
764 #endif /* SQLITE_MEMDEBUG */ |
|
765 |
|
766 static void test_memdebug_log_clear(){ |
|
767 Tcl_HashSearch search; |
|
768 Tcl_HashEntry *pEntry; |
|
769 for( |
|
770 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); |
|
771 pEntry; |
|
772 pEntry=Tcl_NextHashEntry(&search) |
|
773 ){ |
|
774 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); |
|
775 Tcl_Free((char *)pLog); |
|
776 } |
|
777 Tcl_DeleteHashTable(&aMallocLog); |
|
778 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); |
|
779 } |
|
780 |
|
781 static int test_memdebug_log( |
|
782 void * clientData, |
|
783 Tcl_Interp *interp, |
|
784 int objc, |
|
785 Tcl_Obj *CONST objv[] |
|
786 ){ |
|
787 static int isInit = 0; |
|
788 int iSub; |
|
789 |
|
790 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" }; |
|
791 enum MB_enum { |
|
792 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC |
|
793 }; |
|
794 |
|
795 if( !isInit ){ |
|
796 #ifdef SQLITE_MEMDEBUG |
|
797 extern void sqlite3MemdebugBacktraceCallback( |
|
798 void (*xBacktrace)(int, int, void **)); |
|
799 sqlite3MemdebugBacktraceCallback(test_memdebug_callback); |
|
800 #endif |
|
801 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); |
|
802 isInit = 1; |
|
803 } |
|
804 |
|
805 if( objc<2 ){ |
|
806 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); |
|
807 } |
|
808 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){ |
|
809 return TCL_ERROR; |
|
810 } |
|
811 |
|
812 switch( (enum MB_enum)iSub ){ |
|
813 case MB_LOG_START: |
|
814 mallocLogEnabled = 1; |
|
815 break; |
|
816 case MB_LOG_STOP: |
|
817 mallocLogEnabled = 0; |
|
818 break; |
|
819 case MB_LOG_DUMP: { |
|
820 Tcl_HashSearch search; |
|
821 Tcl_HashEntry *pEntry; |
|
822 Tcl_Obj *pRet = Tcl_NewObj(); |
|
823 |
|
824 assert(sizeof(int)==sizeof(void*)); |
|
825 |
|
826 for( |
|
827 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); |
|
828 pEntry; |
|
829 pEntry=Tcl_NextHashEntry(&search) |
|
830 ){ |
|
831 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2]; |
|
832 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); |
|
833 int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry); |
|
834 int ii; |
|
835 |
|
836 apElem[0] = Tcl_NewIntObj(pLog->nCall); |
|
837 apElem[1] = Tcl_NewIntObj(pLog->nByte); |
|
838 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){ |
|
839 apElem[ii+2] = Tcl_NewIntObj(aKey[ii]); |
|
840 } |
|
841 |
|
842 Tcl_ListObjAppendElement(interp, pRet, |
|
843 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem) |
|
844 ); |
|
845 } |
|
846 |
|
847 Tcl_SetObjResult(interp, pRet); |
|
848 break; |
|
849 } |
|
850 case MB_LOG_CLEAR: { |
|
851 test_memdebug_log_clear(); |
|
852 break; |
|
853 } |
|
854 |
|
855 case MB_LOG_SYNC: { |
|
856 #ifdef SQLITE_MEMDEBUG |
|
857 extern void sqlite3MemdebugSync(); |
|
858 test_memdebug_log_clear(); |
|
859 mallocLogEnabled = 1; |
|
860 sqlite3MemdebugSync(); |
|
861 #endif |
|
862 break; |
|
863 } |
|
864 } |
|
865 |
|
866 return TCL_OK; |
|
867 } |
|
868 |
|
869 /* |
|
870 ** Usage: sqlite3_config_scratch SIZE N |
|
871 ** |
|
872 ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH. |
|
873 ** The buffer is static and is of limited size. N might be |
|
874 ** adjusted downward as needed to accomodate the requested size. |
|
875 ** The revised value of N is returned. |
|
876 ** |
|
877 ** A negative SIZE causes the buffer pointer to be NULL. |
|
878 */ |
|
879 static int test_config_scratch( |
|
880 void * clientData, |
|
881 Tcl_Interp *interp, |
|
882 int objc, |
|
883 Tcl_Obj *CONST objv[] |
|
884 ){ |
|
885 int sz, N, rc; |
|
886 Tcl_Obj *pResult; |
|
887 static char *buf = 0; |
|
888 if( objc!=3 ){ |
|
889 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); |
|
890 return TCL_ERROR; |
|
891 } |
|
892 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; |
|
893 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; |
|
894 free(buf); |
|
895 if( sz<0 ){ |
|
896 buf = 0; |
|
897 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0); |
|
898 }else{ |
|
899 buf = malloc( sz*N + 1 ); |
|
900 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N); |
|
901 } |
|
902 pResult = Tcl_NewObj(); |
|
903 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); |
|
904 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); |
|
905 Tcl_SetObjResult(interp, pResult); |
|
906 return TCL_OK; |
|
907 } |
|
908 |
|
909 /* |
|
910 ** Usage: sqlite3_config_pagecache SIZE N |
|
911 ** |
|
912 ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. |
|
913 ** The buffer is static and is of limited size. N might be |
|
914 ** adjusted downward as needed to accomodate the requested size. |
|
915 ** The revised value of N is returned. |
|
916 ** |
|
917 ** A negative SIZE causes the buffer pointer to be NULL. |
|
918 */ |
|
919 static int test_config_pagecache( |
|
920 void * clientData, |
|
921 Tcl_Interp *interp, |
|
922 int objc, |
|
923 Tcl_Obj *CONST objv[] |
|
924 ){ |
|
925 int sz, N, rc; |
|
926 Tcl_Obj *pResult; |
|
927 static char *buf = 0; |
|
928 if( objc!=3 ){ |
|
929 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); |
|
930 return TCL_ERROR; |
|
931 } |
|
932 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; |
|
933 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; |
|
934 free(buf); |
|
935 if( sz<0 ){ |
|
936 buf = 0; |
|
937 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0); |
|
938 }else{ |
|
939 buf = malloc( sz*N ); |
|
940 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N); |
|
941 } |
|
942 pResult = Tcl_NewObj(); |
|
943 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); |
|
944 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); |
|
945 Tcl_SetObjResult(interp, pResult); |
|
946 return TCL_OK; |
|
947 } |
|
948 |
|
949 /* |
|
950 ** Usage: sqlite3_config_memstatus BOOLEAN |
|
951 ** |
|
952 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS. |
|
953 */ |
|
954 static int test_config_memstatus( |
|
955 void * clientData, |
|
956 Tcl_Interp *interp, |
|
957 int objc, |
|
958 Tcl_Obj *CONST objv[] |
|
959 ){ |
|
960 int enable, rc; |
|
961 if( objc!=2 ){ |
|
962 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); |
|
963 return TCL_ERROR; |
|
964 } |
|
965 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR; |
|
966 rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable); |
|
967 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); |
|
968 return TCL_OK; |
|
969 } |
|
970 |
|
971 /* |
|
972 ** Usage: sqlite3_config_chunkalloc |
|
973 ** |
|
974 */ |
|
975 static int test_config_chunkalloc( |
|
976 void * clientData, |
|
977 Tcl_Interp *interp, |
|
978 int objc, |
|
979 Tcl_Obj *CONST objv[] |
|
980 ){ |
|
981 int rc; |
|
982 int nThreshold; |
|
983 if( objc!=2 ){ |
|
984 Tcl_WrongNumArgs(interp, 1, objv, "THRESHOLD"); |
|
985 return TCL_ERROR; |
|
986 } |
|
987 if( Tcl_GetIntFromObj(interp, objv[1], &nThreshold) ) return TCL_ERROR; |
|
988 rc = sqlite3_config(SQLITE_CONFIG_CHUNKALLOC, nThreshold); |
|
989 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); |
|
990 return TCL_OK; |
|
991 } |
|
992 |
|
993 /* |
|
994 ** Usage: sqlite3_config_lookaside SIZE COUNT |
|
995 ** |
|
996 */ |
|
997 static int test_config_lookaside( |
|
998 void * clientData, |
|
999 Tcl_Interp *interp, |
|
1000 int objc, |
|
1001 Tcl_Obj *CONST objv[] |
|
1002 ){ |
|
1003 int rc; |
|
1004 int sz, cnt; |
|
1005 if( objc!=3 ){ |
|
1006 Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT"); |
|
1007 return TCL_ERROR; |
|
1008 } |
|
1009 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; |
|
1010 if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR; |
|
1011 rc = sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt); |
|
1012 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); |
|
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 */ |
|
1024 static int 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 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, 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: |
|
1058 ** |
|
1059 ** sqlite3_config_heap NBYTE NMINALLOC |
|
1060 */ |
|
1061 static int test_config_heap( |
|
1062 void * clientData, |
|
1063 Tcl_Interp *interp, |
|
1064 int objc, |
|
1065 Tcl_Obj *CONST objv[] |
|
1066 ){ |
|
1067 static char *zBuf; /* Use this memory */ |
|
1068 static int szBuf; /* Bytes allocated for zBuf */ |
|
1069 int nByte; /* Size of buffer to pass to sqlite3_config() */ |
|
1070 int nMinAlloc; /* Size of minimum allocation */ |
|
1071 int rc; /* Return code of sqlite3_config() */ |
|
1072 |
|
1073 Tcl_Obj * CONST *aArg = &objv[1]; |
|
1074 int nArg = objc-1; |
|
1075 |
|
1076 if( nArg!=2 ){ |
|
1077 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC"); |
|
1078 return TCL_ERROR; |
|
1079 } |
|
1080 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR; |
|
1081 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR; |
|
1082 |
|
1083 if( nByte==0 ){ |
|
1084 free( zBuf ); |
|
1085 zBuf = 0; |
|
1086 szBuf = 0; |
|
1087 rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0); |
|
1088 }else{ |
|
1089 zBuf = realloc(zBuf, nByte); |
|
1090 szBuf = nByte; |
|
1091 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc); |
|
1092 } |
|
1093 |
|
1094 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); |
|
1095 return TCL_OK; |
|
1096 } |
|
1097 |
|
1098 /* |
|
1099 ** tclcmd: sqlite3_config_error [DB] |
|
1100 ** |
|
1101 ** Invoke sqlite3_config() or sqlite3_db_config() with invalid |
|
1102 ** opcodes and verify that they return errors. |
|
1103 */ |
|
1104 static int test_config_error( |
|
1105 void * clientData, |
|
1106 Tcl_Interp *interp, |
|
1107 int objc, |
|
1108 Tcl_Obj *CONST objv[] |
|
1109 ){ |
|
1110 sqlite3 *db; |
|
1111 int getDbPointer(Tcl_Interp*, const char*, sqlite3**); |
|
1112 |
|
1113 if( objc!=2 && objc!=1 ){ |
|
1114 Tcl_WrongNumArgs(interp, 1, objv, "[DB]"); |
|
1115 return TCL_ERROR; |
|
1116 } |
|
1117 if( objc==2 ){ |
|
1118 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
|
1119 if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){ |
|
1120 Tcl_AppendResult(interp, |
|
1121 "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR", |
|
1122 (char*)0); |
|
1123 return TCL_ERROR; |
|
1124 } |
|
1125 }else{ |
|
1126 if( sqlite3_config(99999)!=SQLITE_ERROR ){ |
|
1127 Tcl_AppendResult(interp, |
|
1128 "sqlite3_config(99999) does not return SQLITE_ERROR", |
|
1129 (char*)0); |
|
1130 return TCL_ERROR; |
|
1131 } |
|
1132 } |
|
1133 return TCL_OK; |
|
1134 } |
|
1135 |
|
1136 /* |
|
1137 ** Usage: |
|
1138 ** |
|
1139 ** sqlite3_dump_memsys3 FILENAME |
|
1140 ** sqlite3_dump_memsys5 FILENAME |
|
1141 ** |
|
1142 ** Write a summary of unfreed memsys3 allocations to FILENAME. |
|
1143 */ |
|
1144 static int test_dump_memsys3( |
|
1145 void * clientData, |
|
1146 Tcl_Interp *interp, |
|
1147 int objc, |
|
1148 Tcl_Obj *CONST objv[] |
|
1149 ){ |
|
1150 if( objc!=2 ){ |
|
1151 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); |
|
1152 return TCL_ERROR; |
|
1153 } |
|
1154 |
|
1155 switch( (int)clientData ){ |
|
1156 case 3: { |
|
1157 #ifdef SQLITE_ENABLE_MEMSYS3 |
|
1158 extern void sqlite3Memsys3Dump(const char*); |
|
1159 sqlite3Memsys3Dump(Tcl_GetString(objv[1])); |
|
1160 break; |
|
1161 #endif |
|
1162 } |
|
1163 case 5: { |
|
1164 #ifdef SQLITE_ENABLE_MEMSYS5 |
|
1165 extern void sqlite3Memsys5Dump(const char*); |
|
1166 sqlite3Memsys5Dump(Tcl_GetString(objv[1])); |
|
1167 break; |
|
1168 #endif |
|
1169 } |
|
1170 } |
|
1171 return TCL_OK; |
|
1172 } |
|
1173 |
|
1174 /* |
|
1175 ** Usage: sqlite3_status OPCODE RESETFLAG |
|
1176 ** |
|
1177 ** Return a list of three elements which are the sqlite3_status() return |
|
1178 ** code, the current value, and the high-water mark value. |
|
1179 */ |
|
1180 static int test_status( |
|
1181 void * clientData, |
|
1182 Tcl_Interp *interp, |
|
1183 int objc, |
|
1184 Tcl_Obj *CONST objv[] |
|
1185 ){ |
|
1186 int rc, iValue, mxValue; |
|
1187 int i, op, resetFlag; |
|
1188 const char *zOpName; |
|
1189 static const struct { |
|
1190 const char *zName; |
|
1191 int op; |
|
1192 } aOp[] = { |
|
1193 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED }, |
|
1194 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE }, |
|
1195 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED }, |
|
1196 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW }, |
|
1197 { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE }, |
|
1198 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED }, |
|
1199 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW }, |
|
1200 { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE }, |
|
1201 { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK }, |
|
1202 }; |
|
1203 Tcl_Obj *pResult; |
|
1204 if( objc!=3 ){ |
|
1205 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); |
|
1206 return TCL_ERROR; |
|
1207 } |
|
1208 zOpName = Tcl_GetString(objv[1]); |
|
1209 for(i=0; i<ArraySize(aOp); i++){ |
|
1210 if( strcmp(aOp[i].zName, zOpName)==0 ){ |
|
1211 op = aOp[i].op; |
|
1212 break; |
|
1213 } |
|
1214 } |
|
1215 if( i>=ArraySize(aOp) ){ |
|
1216 if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR; |
|
1217 } |
|
1218 if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR; |
|
1219 iValue = 0; |
|
1220 mxValue = 0; |
|
1221 rc = sqlite3_status(op, &iValue, &mxValue, resetFlag); |
|
1222 pResult = Tcl_NewObj(); |
|
1223 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); |
|
1224 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); |
|
1225 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); |
|
1226 Tcl_SetObjResult(interp, pResult); |
|
1227 return TCL_OK; |
|
1228 } |
|
1229 |
|
1230 /* |
|
1231 ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG |
|
1232 ** |
|
1233 ** Return a list of three elements which are the sqlite3_db_status() return |
|
1234 ** code, the current value, and the high-water mark value. |
|
1235 */ |
|
1236 static int test_db_status( |
|
1237 void * clientData, |
|
1238 Tcl_Interp *interp, |
|
1239 int objc, |
|
1240 Tcl_Obj *CONST objv[] |
|
1241 ){ |
|
1242 int rc, iValue, mxValue; |
|
1243 int i, op, resetFlag; |
|
1244 const char *zOpName; |
|
1245 sqlite3 *db; |
|
1246 int getDbPointer(Tcl_Interp*, const char*, sqlite3**); |
|
1247 static const struct { |
|
1248 const char *zName; |
|
1249 int op; |
|
1250 } aOp[] = { |
|
1251 { "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED }, |
|
1252 }; |
|
1253 Tcl_Obj *pResult; |
|
1254 if( objc!=4 ){ |
|
1255 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); |
|
1256 return TCL_ERROR; |
|
1257 } |
|
1258 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
|
1259 zOpName = Tcl_GetString(objv[2]); |
|
1260 for(i=0; i<ArraySize(aOp); i++){ |
|
1261 if( strcmp(aOp[i].zName, zOpName)==0 ){ |
|
1262 op = aOp[i].op; |
|
1263 break; |
|
1264 } |
|
1265 } |
|
1266 if( i>=ArraySize(aOp) ){ |
|
1267 if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR; |
|
1268 } |
|
1269 if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR; |
|
1270 iValue = 0; |
|
1271 mxValue = 0; |
|
1272 rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag); |
|
1273 pResult = Tcl_NewObj(); |
|
1274 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); |
|
1275 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); |
|
1276 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); |
|
1277 Tcl_SetObjResult(interp, pResult); |
|
1278 return TCL_OK; |
|
1279 } |
|
1280 |
|
1281 /* |
|
1282 ** install_malloc_faultsim BOOLEAN |
|
1283 */ |
|
1284 static int test_install_malloc_faultsim( |
|
1285 void * clientData, |
|
1286 Tcl_Interp *interp, |
|
1287 int objc, |
|
1288 Tcl_Obj *CONST objv[] |
|
1289 ){ |
|
1290 int rc; |
|
1291 int isInstall; |
|
1292 |
|
1293 if( objc!=2 ){ |
|
1294 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); |
|
1295 return TCL_ERROR; |
|
1296 } |
|
1297 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ |
|
1298 return TCL_ERROR; |
|
1299 } |
|
1300 rc = faultsimInstall(isInstall); |
|
1301 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); |
|
1302 return TCL_OK; |
|
1303 } |
|
1304 |
|
1305 /* |
|
1306 ** Register commands with the TCL interpreter. |
|
1307 */ |
|
1308 int Sqlitetest_malloc_Init(Tcl_Interp *interp){ |
|
1309 static struct { |
|
1310 char *zName; |
|
1311 Tcl_ObjCmdProc *xProc; |
|
1312 int clientData; |
|
1313 } aObjCmd[] = { |
|
1314 { "sqlite3_malloc", test_malloc ,0 }, |
|
1315 { "sqlite3_realloc", test_realloc ,0 }, |
|
1316 { "sqlite3_free", test_free ,0 }, |
|
1317 { "memset", test_memset ,0 }, |
|
1318 { "memget", test_memget ,0 }, |
|
1319 { "sqlite3_memory_used", test_memory_used ,0 }, |
|
1320 { "sqlite3_memory_highwater", test_memory_highwater ,0 }, |
|
1321 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 }, |
|
1322 { "sqlite3_memdebug_dump", test_memdebug_dump ,0 }, |
|
1323 { "sqlite3_memdebug_fail", test_memdebug_fail ,0 }, |
|
1324 { "sqlite3_memdebug_pending", test_memdebug_pending ,0 }, |
|
1325 { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 }, |
|
1326 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 }, |
|
1327 { "sqlite3_memdebug_log", test_memdebug_log ,0 }, |
|
1328 { "sqlite3_config_scratch", test_config_scratch ,0 }, |
|
1329 { "sqlite3_config_pagecache", test_config_pagecache ,0 }, |
|
1330 { "sqlite3_status", test_status ,0 }, |
|
1331 { "sqlite3_db_status", test_db_status ,0 }, |
|
1332 { "install_malloc_faultsim", test_install_malloc_faultsim ,0 }, |
|
1333 { "sqlite3_config_heap", test_config_heap ,0 }, |
|
1334 { "sqlite3_config_memstatus", test_config_memstatus ,0 }, |
|
1335 { "sqlite3_config_chunkalloc", test_config_chunkalloc ,0 }, |
|
1336 { "sqlite3_config_lookaside", test_config_lookaside ,0 }, |
|
1337 { "sqlite3_config_error", test_config_error ,0 }, |
|
1338 { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 }, |
|
1339 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, |
|
1340 { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 } |
|
1341 }; |
|
1342 int i; |
|
1343 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ |
|
1344 ClientData c = (ClientData)aObjCmd[i].clientData; |
|
1345 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0); |
|
1346 } |
|
1347 return TCL_OK; |
|
1348 } |
|
1349 #endif |