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 }