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