modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/lsm1/lsm-test/lsmtest_mem.c (about)

     1  
     2  #include <stdio.h>
     3  #include <assert.h>
     4  #include <string.h>
     5  
     6  #define ArraySize(x) ((int)(sizeof(x) / sizeof((x)[0])))
     7  
     8  #define MIN(x,y) ((x)<(y) ? (x) : (y))
     9  
    10  typedef unsigned int  u32;
    11  typedef unsigned char u8;
    12  typedef long long int i64;
    13  typedef unsigned long long int u64;
    14  
    15  #if defined(__GLIBC__) && defined(LSM_DEBUG_MEM)
    16    extern int backtrace(void**,int);
    17    extern void backtrace_symbols_fd(void*const*,int,int);
    18  # define TM_BACKTRACE 12
    19  #else
    20  # define backtrace(A,B) 1
    21  # define backtrace_symbols_fd(A,B,C)
    22  #endif
    23  
    24  
    25  typedef struct TmBlockHdr TmBlockHdr;
    26  typedef struct TmAgg TmAgg;
    27  typedef struct TmGlobal TmGlobal;
    28  
    29  struct TmGlobal {
    30    /* Linked list of all currently outstanding allocations. And a table of
    31    ** all allocations, past and present, indexed by backtrace() info.  */
    32    TmBlockHdr *pFirst;
    33  #ifdef TM_BACKTRACE
    34    TmAgg *aHash[10000];
    35  #endif
    36  
    37    /* Underlying malloc/realloc/free functions */
    38    void *(*xMalloc)(int);          /* underlying malloc(3) function */
    39    void *(*xRealloc)(void *, int); /* underlying realloc(3) function */
    40    void (*xFree)(void *);          /* underlying free(3) function */
    41  
    42    /* Mutex to protect pFirst and aHash */
    43    void (*xEnterMutex)(TmGlobal*); /* Call this to enter the mutex */
    44    void (*xLeaveMutex)(TmGlobal*); /* Call this to leave mutex */
    45    void (*xDelMutex)(TmGlobal*);   /* Call this to delete mutex */
    46    void *pMutex;                   /* Mutex handle */
    47  
    48    void *(*xSaveMalloc)(void *, size_t);
    49    void *(*xSaveRealloc)(void *, void *, size_t);
    50    void (*xSaveFree)(void *, void *);
    51  
    52    /* OOM injection scheduling. If nCountdown is greater than zero when a 
    53    ** malloc attempt is made, it is decremented. If this means nCountdown 
    54    ** transitions from 1 to 0, then the allocation fails. If bPersist is true 
    55    ** when this happens, nCountdown is then incremented back to 1 (so that the 
    56    ** next attempt fails too).  
    57    */
    58    int nCountdown;
    59    int bPersist;
    60    int bEnable;
    61    void (*xHook)(void *);
    62    void *pHookCtx;
    63  };
    64  
    65  struct TmBlockHdr {
    66    TmBlockHdr *pNext;
    67    TmBlockHdr *pPrev;
    68    int nByte;
    69  #ifdef TM_BACKTRACE
    70    TmAgg *pAgg;
    71  #endif
    72    u32 iForeGuard;
    73  };
    74  
    75  #ifdef TM_BACKTRACE
    76  struct TmAgg {
    77    int nAlloc;                     /* Number of allocations at this path */
    78    int nByte;                      /* Total number of bytes allocated */
    79    int nOutAlloc;                  /* Number of outstanding allocations */
    80    int nOutByte;                   /* Number of outstanding bytes */
    81    void *aFrame[TM_BACKTRACE];     /* backtrace() output */
    82    TmAgg *pNext;                   /* Next object in hash-table collision */
    83  };
    84  #endif
    85  
    86  #define FOREGUARD 0x80F5E153
    87  #define REARGUARD 0xE4676B53
    88  static const u32 rearguard = REARGUARD;
    89  
    90  #define ROUND8(x) (((x)+7)&~7)
    91  
    92  #define BLOCK_HDR_SIZE (ROUND8( sizeof(TmBlockHdr) ))
    93  
    94  static void lsmtest_oom_error(void){
    95    static int nErr = 0;
    96    nErr++;
    97  }
    98  
    99  static void tmEnterMutex(TmGlobal *pTm){
   100    pTm->xEnterMutex(pTm);
   101  }
   102  static void tmLeaveMutex(TmGlobal *pTm){
   103    pTm->xLeaveMutex(pTm);
   104  }
   105  
   106  static void *tmMalloc(TmGlobal *pTm, int nByte){
   107    TmBlockHdr *pNew;               /* New allocation header block */
   108    u8 *pUser;                      /* Return value */
   109    int nReq;                       /* Total number of bytes requested */
   110  
   111    assert( sizeof(rearguard)==4 );
   112    nReq = BLOCK_HDR_SIZE + nByte + 4;
   113    pNew = (TmBlockHdr *)pTm->xMalloc(nReq);
   114    memset(pNew, 0, sizeof(TmBlockHdr));
   115  
   116    tmEnterMutex(pTm);
   117    assert( pTm->nCountdown>=0 );
   118    assert( pTm->bPersist==0 || pTm->bPersist==1 );
   119  
   120    if( pTm->bEnable && pTm->nCountdown==1 ){
   121      /* Simulate an OOM error. */
   122      lsmtest_oom_error();
   123      pTm->xFree(pNew);
   124      pTm->nCountdown = pTm->bPersist;
   125      if( pTm->xHook ) pTm->xHook(pTm->pHookCtx);
   126      pUser = 0;
   127    }else{
   128      if( pTm->bEnable && pTm->nCountdown ) pTm->nCountdown--;
   129  
   130      pNew->iForeGuard = FOREGUARD;
   131      pNew->nByte = nByte;
   132      pNew->pNext = pTm->pFirst;
   133  
   134      if( pTm->pFirst ){
   135        pTm->pFirst->pPrev = pNew;
   136      }
   137      pTm->pFirst = pNew;
   138  
   139      pUser = &((u8 *)pNew)[BLOCK_HDR_SIZE];
   140      memset(pUser, 0x56, nByte);
   141      memcpy(&pUser[nByte], &rearguard, 4);
   142  
   143  #ifdef TM_BACKTRACE
   144      {
   145        TmAgg *pAgg;
   146        int i;
   147        u32 iHash = 0;
   148        void *aFrame[TM_BACKTRACE];
   149        memset(aFrame, 0, sizeof(aFrame));
   150        backtrace(aFrame, TM_BACKTRACE);
   151  
   152        for(i=0; i<ArraySize(aFrame); i++){
   153          iHash += (u64)(aFrame[i]) + (iHash<<3);
   154        }
   155        iHash = iHash % ArraySize(pTm->aHash);
   156  
   157        for(pAgg=pTm->aHash[iHash]; pAgg; pAgg=pAgg->pNext){
   158          if( memcmp(pAgg->aFrame, aFrame, sizeof(aFrame))==0 ) break;
   159        }
   160        if( !pAgg ){
   161          pAgg = (TmAgg *)pTm->xMalloc(sizeof(TmAgg));
   162          memset(pAgg, 0, sizeof(TmAgg));
   163          memcpy(pAgg->aFrame, aFrame, sizeof(aFrame));
   164          pAgg->pNext = pTm->aHash[iHash];
   165          pTm->aHash[iHash] = pAgg;
   166        }
   167        pAgg->nAlloc++;
   168        pAgg->nByte += nByte;
   169        pAgg->nOutAlloc++;
   170        pAgg->nOutByte += nByte;
   171        pNew->pAgg = pAgg;
   172      }
   173  #endif
   174    }
   175  
   176    tmLeaveMutex(pTm);
   177    return pUser;
   178  }
   179  
   180  static void tmFree(TmGlobal *pTm, void *p){
   181    if( p ){
   182      TmBlockHdr *pHdr;
   183      u8 *pUser = (u8 *)p;
   184  
   185      tmEnterMutex(pTm);
   186      pHdr = (TmBlockHdr *)(pUser - BLOCK_HDR_SIZE);
   187      assert( pHdr->iForeGuard==FOREGUARD );
   188      assert( 0==memcmp(&pUser[pHdr->nByte], &rearguard, 4) );
   189  
   190      if( pHdr->pPrev ){
   191        assert( pHdr->pPrev->pNext==pHdr );
   192        pHdr->pPrev->pNext = pHdr->pNext;
   193      }else{
   194        assert( pHdr==pTm->pFirst );
   195        pTm->pFirst = pHdr->pNext;
   196      }
   197      if( pHdr->pNext ){
   198        assert( pHdr->pNext->pPrev==pHdr );
   199        pHdr->pNext->pPrev = pHdr->pPrev;
   200      }
   201  
   202  #ifdef TM_BACKTRACE
   203      pHdr->pAgg->nOutAlloc--;
   204      pHdr->pAgg->nOutByte -= pHdr->nByte;
   205  #endif
   206  
   207      tmLeaveMutex(pTm);
   208      memset(pUser, 0x58, pHdr->nByte);
   209      memset(pHdr, 0x57, sizeof(TmBlockHdr));
   210      pTm->xFree(pHdr);
   211    }
   212  }
   213  
   214  static void *tmRealloc(TmGlobal *pTm, void *p, int nByte){
   215    void *pNew;
   216  
   217    pNew = tmMalloc(pTm, nByte);
   218    if( pNew && p ){
   219      TmBlockHdr *pHdr;
   220      u8 *pUser = (u8 *)p;
   221      pHdr = (TmBlockHdr *)(pUser - BLOCK_HDR_SIZE);
   222      memcpy(pNew, p, MIN(nByte, pHdr->nByte));
   223      tmFree(pTm, p);
   224    }
   225    return pNew;
   226  }
   227  
   228  static void tmMallocOom(
   229    TmGlobal *pTm, 
   230    int nCountdown, 
   231    int bPersist,
   232    void (*xHook)(void *),
   233    void *pHookCtx
   234  ){
   235    assert( nCountdown>=0 );
   236    assert( bPersist==0 || bPersist==1 );
   237    pTm->nCountdown = nCountdown;
   238    pTm->bPersist = bPersist;
   239    pTm->xHook = xHook;
   240    pTm->pHookCtx = pHookCtx;
   241    pTm->bEnable = 1;
   242  }
   243  
   244  static void tmMallocOomEnable(
   245    TmGlobal *pTm, 
   246    int bEnable
   247  ){
   248    pTm->bEnable = bEnable;
   249  }
   250  
   251  static void tmMallocCheck(
   252    TmGlobal *pTm,
   253    int *pnLeakAlloc,
   254    int *pnLeakByte,
   255    FILE *pFile
   256  ){
   257    TmBlockHdr *pHdr;
   258    int nLeak = 0;
   259    int nByte = 0;
   260  
   261    if( pTm==0 ) return;
   262  
   263    for(pHdr=pTm->pFirst; pHdr; pHdr=pHdr->pNext){
   264      nLeak++; 
   265      nByte += pHdr->nByte;
   266    }
   267    if( pnLeakAlloc ) *pnLeakAlloc = nLeak;
   268    if( pnLeakByte ) *pnLeakByte = nByte;
   269  
   270  #ifdef TM_BACKTRACE
   271    if( pFile ){
   272      int i;
   273      fprintf(pFile, "LEAKS\n");
   274      for(i=0; i<ArraySize(pTm->aHash); i++){
   275        TmAgg *pAgg;
   276        for(pAgg=pTm->aHash[i]; pAgg; pAgg=pAgg->pNext){
   277          if( pAgg->nOutAlloc ){
   278            int j;
   279            fprintf(pFile, "%d %d ", pAgg->nOutByte, pAgg->nOutAlloc);
   280            for(j=0; j<TM_BACKTRACE; j++){
   281              fprintf(pFile, "%p ", pAgg->aFrame[j]);
   282            }
   283            fprintf(pFile, "\n");
   284          }
   285        }
   286      }
   287      fprintf(pFile, "\nALLOCATIONS\n");
   288      for(i=0; i<ArraySize(pTm->aHash); i++){
   289        TmAgg *pAgg;
   290        for(pAgg=pTm->aHash[i]; pAgg; pAgg=pAgg->pNext){
   291          int j;
   292          fprintf(pFile, "%d %d ", pAgg->nByte, pAgg->nAlloc);
   293          for(j=0; j<TM_BACKTRACE; j++) fprintf(pFile, "%p ", pAgg->aFrame[j]);
   294          fprintf(pFile, "\n");
   295        }
   296      }
   297    }
   298  #else
   299    (void)pFile;
   300  #endif
   301  }
   302  
   303  
   304  #include "lsm.h"
   305  #include "stdlib.h"
   306  
   307  typedef struct LsmMutex LsmMutex;
   308  struct LsmMutex {
   309    lsm_env *pEnv;
   310    lsm_mutex *pMutex;
   311  };
   312  
   313  static void tmLsmMutexEnter(TmGlobal *pTm){
   314    LsmMutex *p = (LsmMutex *)pTm->pMutex;
   315    p->pEnv->xMutexEnter(p->pMutex);
   316  }
   317  static void tmLsmMutexLeave(TmGlobal *pTm){
   318    LsmMutex *p = (LsmMutex *)(pTm->pMutex);
   319    p->pEnv->xMutexLeave(p->pMutex);
   320  }
   321  static void tmLsmMutexDel(TmGlobal *pTm){
   322    LsmMutex *p = (LsmMutex *)pTm->pMutex;
   323    pTm->xFree(p);
   324  }
   325  static void *tmLsmMalloc(int n){ return malloc(n); }
   326  static void tmLsmFree(void *ptr){ free(ptr); }
   327  static void *tmLsmRealloc(void *ptr, int n){ return realloc(ptr, n); }
   328  
   329  static void *tmLsmEnvMalloc(lsm_env *p, size_t n){ 
   330    return tmMalloc((TmGlobal *)(p->pMemCtx), n); 
   331  }
   332  static void tmLsmEnvFree(lsm_env *p, void *ptr){ 
   333    tmFree((TmGlobal *)(p->pMemCtx), ptr); 
   334  }
   335  static void *tmLsmEnvRealloc(lsm_env *p, void *ptr, size_t n){ 
   336    return tmRealloc((TmGlobal *)(p->pMemCtx), ptr, n);
   337  }
   338  
   339  void testMallocInstall(lsm_env *pEnv){
   340    TmGlobal *pGlobal;
   341    LsmMutex *pMutex;
   342    assert( pEnv->pMemCtx==0 );
   343  
   344    /* Allocate and populate a TmGlobal structure. */
   345    pGlobal = (TmGlobal *)tmLsmMalloc(sizeof(TmGlobal));
   346    memset(pGlobal, 0, sizeof(TmGlobal));
   347    pGlobal->xMalloc = tmLsmMalloc;
   348    pGlobal->xRealloc = tmLsmRealloc;
   349    pGlobal->xFree = tmLsmFree;
   350    pMutex = (LsmMutex *)pGlobal->xMalloc(sizeof(LsmMutex));
   351    pMutex->pEnv = pEnv;
   352    pEnv->xMutexStatic(pEnv, LSM_MUTEX_HEAP, &pMutex->pMutex);
   353    pGlobal->xEnterMutex = tmLsmMutexEnter;
   354    pGlobal->xLeaveMutex = tmLsmMutexLeave;
   355    pGlobal->xDelMutex = tmLsmMutexDel;
   356    pGlobal->pMutex = (void *)pMutex;
   357  
   358    pGlobal->xSaveMalloc = pEnv->xMalloc;
   359    pGlobal->xSaveRealloc = pEnv->xRealloc;
   360    pGlobal->xSaveFree = pEnv->xFree;
   361  
   362    /* Set up pEnv to the use the new TmGlobal */
   363    pEnv->pMemCtx = (void *)pGlobal;
   364    pEnv->xMalloc = tmLsmEnvMalloc;
   365    pEnv->xRealloc = tmLsmEnvRealloc;
   366    pEnv->xFree = tmLsmEnvFree;
   367  }
   368  
   369  void testMallocUninstall(lsm_env *pEnv){
   370    TmGlobal *p = (TmGlobal *)pEnv->pMemCtx;
   371    pEnv->pMemCtx = 0;
   372    if( p ){
   373      pEnv->xMalloc = p->xSaveMalloc;
   374      pEnv->xRealloc = p->xSaveRealloc;
   375      pEnv->xFree = p->xSaveFree;
   376      p->xDelMutex(p);
   377      tmLsmFree(p);
   378    }
   379  }
   380  
   381  void testMallocCheck(
   382    lsm_env *pEnv,
   383    int *pnLeakAlloc,
   384    int *pnLeakByte,
   385    FILE *pFile
   386  ){
   387    if( pEnv->pMemCtx==0 ){
   388      *pnLeakAlloc = 0;
   389      *pnLeakByte = 0;
   390    }else{
   391      tmMallocCheck((TmGlobal *)(pEnv->pMemCtx), pnLeakAlloc, pnLeakByte, pFile);
   392    }
   393  }
   394  
   395  void testMallocOom(
   396    lsm_env *pEnv, 
   397    int nCountdown, 
   398    int bPersist,
   399    void (*xHook)(void *),
   400    void *pHookCtx
   401  ){
   402    TmGlobal *pTm = (TmGlobal *)(pEnv->pMemCtx);
   403    tmMallocOom(pTm, nCountdown, bPersist, xHook, pHookCtx);
   404  }
   405  
   406  void testMallocOomEnable(lsm_env *pEnv, int bEnable){
   407    TmGlobal *pTm = (TmGlobal *)(pEnv->pMemCtx);
   408    tmMallocOomEnable(pTm, bEnable);
   409  }