drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 1 | /* |
| 2 | ** 2007 August 15 |
| 3 | ** |
| 4 | ** The author disclaims copyright to this source code. In place of |
| 5 | ** a legal notice, here is a blessing: |
| 6 | ** |
| 7 | ** May you do good and not evil. |
| 8 | ** May you find forgiveness for yourself and forgive others. |
| 9 | ** May you share freely, never taking more than you give. |
| 10 | ** |
| 11 | ************************************************************************* |
| 12 | ** This file contains the C functions that implement a memory |
| 13 | ** allocation subsystem for use by SQLite. |
| 14 | ** |
danielk1977 | 6f332c1 | 2008-03-21 14:22:44 +0000 | [diff] [blame] | 15 | ** $Id: mem2.c,v 1.23 2008/03/21 14:22:44 danielk1977 Exp $ |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 16 | */ |
drh | 0d18020 | 2008-02-14 23:26:56 +0000 | [diff] [blame] | 17 | #include "sqliteInt.h" |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 18 | |
| 19 | /* |
| 20 | ** This version of the memory allocator is used only if the |
drh | 0d18020 | 2008-02-14 23:26:56 +0000 | [diff] [blame] | 21 | ** SQLITE_MEMDEBUG macro is defined |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 22 | */ |
drh | 0d18020 | 2008-02-14 23:26:56 +0000 | [diff] [blame] | 23 | #ifdef SQLITE_MEMDEBUG |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 24 | |
| 25 | /* |
| 26 | ** The backtrace functionality is only available with GLIBC |
| 27 | */ |
| 28 | #ifdef __GLIBC__ |
| 29 | extern int backtrace(void**,int); |
| 30 | extern void backtrace_symbols_fd(void*const*,int,int); |
| 31 | #else |
| 32 | # define backtrace(A,B) 0 |
| 33 | # define backtrace_symbols_fd(A,B,C) |
| 34 | #endif |
drh | 0d18020 | 2008-02-14 23:26:56 +0000 | [diff] [blame] | 35 | #include <stdio.h> |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 36 | |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 37 | /* |
| 38 | ** Each memory allocation looks like this: |
| 39 | ** |
drh | 4a50aac | 2007-08-23 02:47:53 +0000 | [diff] [blame] | 40 | ** ------------------------------------------------------------------------ |
| 41 | ** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard | |
| 42 | ** ------------------------------------------------------------------------ |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 43 | ** |
| 44 | ** The application code sees only a pointer to the allocation. We have |
| 45 | ** to back up from the allocation pointer to find the MemBlockHdr. The |
| 46 | ** MemBlockHdr tells us the size of the allocation and the number of |
| 47 | ** backtrace pointers. There is also a guard word at the end of the |
| 48 | ** MemBlockHdr. |
| 49 | */ |
| 50 | struct MemBlockHdr { |
| 51 | struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */ |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 52 | int iSize; /* Size of this allocation */ |
| 53 | char nBacktrace; /* Number of backtraces on this alloc */ |
| 54 | char nBacktraceSlots; /* Available backtrace slots */ |
| 55 | short nTitle; /* Bytes of title; includes '\0' */ |
| 56 | int iForeGuard; /* Guard word for sanity */ |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 57 | }; |
| 58 | |
| 59 | /* |
| 60 | ** Guard words |
| 61 | */ |
| 62 | #define FOREGUARD 0x80F5E153 |
| 63 | #define REARGUARD 0xE4676B53 |
| 64 | |
| 65 | /* |
drh | d2bb327 | 2007-10-15 19:34:32 +0000 | [diff] [blame] | 66 | ** Number of malloc size increments to track. |
| 67 | */ |
drh | 9c7a60d | 2007-10-19 17:47:24 +0000 | [diff] [blame] | 68 | #define NCSIZE 1000 |
drh | d2bb327 | 2007-10-15 19:34:32 +0000 | [diff] [blame] | 69 | |
| 70 | /* |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 71 | ** All of the static variables used by this module are collected |
| 72 | ** into a single structure named "mem". This is to keep the |
| 73 | ** static variables organized and to reduce namespace pollution |
| 74 | ** when this module is combined with other in the amalgamation. |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 75 | */ |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 76 | static struct { |
| 77 | /* |
| 78 | ** The alarm callback and its arguments. The mem.mutex lock will |
| 79 | ** be held while the callback is running. Recursive calls into |
| 80 | ** the memory subsystem are allowed, but no new callbacks will be |
| 81 | ** issued. The alarmBusy variable is set to prevent recursive |
| 82 | ** callbacks. |
| 83 | */ |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 84 | sqlite3_int64 alarmThreshold; |
| 85 | void (*alarmCallback)(void*, sqlite3_int64, int); |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 86 | void *alarmArg; |
| 87 | int alarmBusy; |
| 88 | |
| 89 | /* |
| 90 | ** Mutex to control access to the memory allocation subsystem. |
| 91 | */ |
| 92 | sqlite3_mutex *mutex; |
| 93 | |
| 94 | /* |
| 95 | ** Current allocation and high-water mark. |
| 96 | */ |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 97 | sqlite3_int64 nowUsed; |
| 98 | sqlite3_int64 mxUsed; |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 99 | |
| 100 | /* |
| 101 | ** Head and tail of a linked list of all outstanding allocations |
| 102 | */ |
| 103 | struct MemBlockHdr *pFirst; |
| 104 | struct MemBlockHdr *pLast; |
| 105 | |
| 106 | /* |
| 107 | ** The number of levels of backtrace to save in new allocations. |
| 108 | */ |
| 109 | int nBacktrace; |
danielk1977 | 6f332c1 | 2008-03-21 14:22:44 +0000 | [diff] [blame] | 110 | void (*xBacktrace)(int, int, void **); |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 111 | |
| 112 | /* |
drh | 4a50aac | 2007-08-23 02:47:53 +0000 | [diff] [blame] | 113 | ** Title text to insert in front of each block |
| 114 | */ |
| 115 | int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ |
| 116 | char zTitle[100]; /* The title text */ |
| 117 | |
drh | d677b3d | 2007-08-20 22:48:41 +0000 | [diff] [blame] | 118 | /* |
| 119 | ** sqlite3MallocDisallow() increments the following counter. |
| 120 | ** sqlite3MallocAllow() decrements it. |
| 121 | */ |
| 122 | int disallow; /* Do not allow memory allocation */ |
drh | d2bb327 | 2007-10-15 19:34:32 +0000 | [diff] [blame] | 123 | |
| 124 | /* |
| 125 | ** Gather statistics on the sizes of memory allocations. |
drh | 9c7a60d | 2007-10-19 17:47:24 +0000 | [diff] [blame] | 126 | ** sizeCnt[i] is the number of allocation attempts of i*8 |
drh | d2bb327 | 2007-10-15 19:34:32 +0000 | [diff] [blame] | 127 | ** bytes. i==NCSIZE is the number of allocation attempts for |
drh | 9c7a60d | 2007-10-19 17:47:24 +0000 | [diff] [blame] | 128 | ** sizes more than NCSIZE*8 bytes. |
drh | d2bb327 | 2007-10-15 19:34:32 +0000 | [diff] [blame] | 129 | */ |
| 130 | int sizeCnt[NCSIZE]; |
| 131 | |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 132 | } mem; |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 133 | |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 134 | |
| 135 | /* |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 136 | ** Enter the mutex mem.mutex. Allocate it if it is not already allocated. |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 137 | */ |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 138 | static void enterMem(void){ |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 139 | if( mem.mutex==0 ){ |
drh | 6bdec4a | 2007-08-16 19:40:16 +0000 | [diff] [blame] | 140 | mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 141 | } |
drh | 6bdec4a | 2007-08-16 19:40:16 +0000 | [diff] [blame] | 142 | sqlite3_mutex_enter(mem.mutex); |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | /* |
| 146 | ** Return the amount of memory currently checked out. |
| 147 | */ |
| 148 | sqlite3_int64 sqlite3_memory_used(void){ |
| 149 | sqlite3_int64 n; |
| 150 | enterMem(); |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 151 | n = mem.nowUsed; |
| 152 | sqlite3_mutex_leave(mem.mutex); |
| 153 | return n; |
| 154 | } |
| 155 | |
| 156 | /* |
| 157 | ** Return the maximum amount of memory that has ever been |
| 158 | ** checked out since either the beginning of this process |
| 159 | ** or since the most recent reset. |
| 160 | */ |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 161 | sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ |
| 162 | sqlite3_int64 n; |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 163 | enterMem(); |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 164 | n = mem.mxUsed; |
| 165 | if( resetFlag ){ |
| 166 | mem.mxUsed = mem.nowUsed; |
| 167 | } |
| 168 | sqlite3_mutex_leave(mem.mutex); |
| 169 | return n; |
| 170 | } |
| 171 | |
| 172 | /* |
| 173 | ** Change the alarm callback |
| 174 | */ |
| 175 | int sqlite3_memory_alarm( |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 176 | void(*xCallback)(void *pArg, sqlite3_int64 used, int N), |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 177 | void *pArg, |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 178 | sqlite3_int64 iThreshold |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 179 | ){ |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 180 | enterMem(); |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 181 | mem.alarmCallback = xCallback; |
| 182 | mem.alarmArg = pArg; |
| 183 | mem.alarmThreshold = iThreshold; |
| 184 | sqlite3_mutex_leave(mem.mutex); |
| 185 | return SQLITE_OK; |
| 186 | } |
| 187 | |
| 188 | /* |
| 189 | ** Trigger the alarm |
| 190 | */ |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 191 | static void sqlite3MemsysAlarm(int nByte){ |
| 192 | void (*xCallback)(void*,sqlite3_int64,int); |
| 193 | sqlite3_int64 nowUsed; |
drh | 6bdec4a | 2007-08-16 19:40:16 +0000 | [diff] [blame] | 194 | void *pArg; |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 195 | if( mem.alarmCallback==0 || mem.alarmBusy ) return; |
| 196 | mem.alarmBusy = 1; |
drh | 6bdec4a | 2007-08-16 19:40:16 +0000 | [diff] [blame] | 197 | xCallback = mem.alarmCallback; |
| 198 | nowUsed = mem.nowUsed; |
| 199 | pArg = mem.alarmArg; |
| 200 | sqlite3_mutex_leave(mem.mutex); |
| 201 | xCallback(pArg, nowUsed, nByte); |
| 202 | sqlite3_mutex_enter(mem.mutex); |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 203 | mem.alarmBusy = 0; |
| 204 | } |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 205 | |
| 206 | /* |
| 207 | ** Given an allocation, find the MemBlockHdr for that allocation. |
| 208 | ** |
| 209 | ** This routine checks the guards at either end of the allocation and |
| 210 | ** if they are incorrect it asserts. |
| 211 | */ |
| 212 | static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ |
| 213 | struct MemBlockHdr *p; |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 214 | int *pInt; |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 215 | |
| 216 | p = (struct MemBlockHdr*)pAllocation; |
| 217 | p--; |
| 218 | assert( p->iForeGuard==FOREGUARD ); |
| 219 | assert( (p->iSize & 3)==0 ); |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 220 | pInt = (int*)pAllocation; |
| 221 | assert( pInt[p->iSize/sizeof(int)]==REARGUARD ); |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 222 | return p; |
| 223 | } |
| 224 | |
| 225 | /* |
danielk1977 | a7a8e14 | 2008-02-13 18:25:27 +0000 | [diff] [blame] | 226 | ** Return the number of bytes currently allocated at address p. |
| 227 | */ |
| 228 | int sqlite3MallocSize(void *p){ |
| 229 | struct MemBlockHdr *pHdr; |
| 230 | if( !p ){ |
| 231 | return 0; |
| 232 | } |
| 233 | pHdr = sqlite3MemsysGetHeader(p); |
| 234 | return pHdr->iSize; |
| 235 | } |
| 236 | |
| 237 | /* |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 238 | ** Allocate nByte bytes of memory. |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 239 | */ |
drh | f3a65f7 | 2007-08-22 20:18:21 +0000 | [diff] [blame] | 240 | void *sqlite3_malloc(int nByte){ |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 241 | struct MemBlockHdr *pHdr; |
| 242 | void **pBt; |
drh | 4a50aac | 2007-08-23 02:47:53 +0000 | [diff] [blame] | 243 | char *z; |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 244 | int *pInt; |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 245 | void *p = 0; |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 246 | int totalSize; |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 247 | |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 248 | if( nByte>0 ){ |
| 249 | enterMem(); |
| 250 | assert( mem.disallow==0 ); |
| 251 | if( mem.alarmCallback!=0 && mem.nowUsed+nByte>=mem.alarmThreshold ){ |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 252 | sqlite3MemsysAlarm(nByte); |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 253 | } |
| 254 | nByte = (nByte+3)&~3; |
drh | d2bb327 | 2007-10-15 19:34:32 +0000 | [diff] [blame] | 255 | if( nByte/8>NCSIZE-1 ){ |
| 256 | mem.sizeCnt[NCSIZE-1]++; |
| 257 | }else{ |
| 258 | mem.sizeCnt[nByte/8]++; |
| 259 | } |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 260 | totalSize = nByte + sizeof(*pHdr) + sizeof(int) + |
| 261 | mem.nBacktrace*sizeof(void*) + mem.nTitle; |
drh | 643167f | 2008-01-22 21:30:53 +0000 | [diff] [blame] | 262 | if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ |
| 263 | p = 0; |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 264 | }else{ |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 265 | p = malloc(totalSize); |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 266 | if( p==0 ){ |
| 267 | sqlite3MemsysAlarm(nByte); |
| 268 | p = malloc(totalSize); |
| 269 | } |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 270 | } |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 271 | if( p ){ |
| 272 | z = p; |
| 273 | pBt = (void**)&z[mem.nTitle]; |
| 274 | pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace]; |
| 275 | pHdr->pNext = 0; |
| 276 | pHdr->pPrev = mem.pLast; |
| 277 | if( mem.pLast ){ |
| 278 | mem.pLast->pNext = pHdr; |
| 279 | }else{ |
| 280 | mem.pFirst = pHdr; |
| 281 | } |
| 282 | mem.pLast = pHdr; |
| 283 | pHdr->iForeGuard = FOREGUARD; |
| 284 | pHdr->nBacktraceSlots = mem.nBacktrace; |
| 285 | pHdr->nTitle = mem.nTitle; |
| 286 | if( mem.nBacktrace ){ |
| 287 | void *aAddr[40]; |
| 288 | pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1; |
| 289 | memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*)); |
danielk1977 | 6f332c1 | 2008-03-21 14:22:44 +0000 | [diff] [blame] | 290 | if( mem.xBacktrace ){ |
| 291 | mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]); |
| 292 | } |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 293 | }else{ |
| 294 | pHdr->nBacktrace = 0; |
| 295 | } |
| 296 | if( mem.nTitle ){ |
| 297 | memcpy(z, mem.zTitle, mem.nTitle); |
| 298 | } |
| 299 | pHdr->iSize = nByte; |
| 300 | pInt = (int*)&pHdr[1]; |
| 301 | pInt[nByte/sizeof(int)] = REARGUARD; |
| 302 | memset(pInt, 0x65, nByte); |
| 303 | mem.nowUsed += nByte; |
| 304 | if( mem.nowUsed>mem.mxUsed ){ |
| 305 | mem.mxUsed = mem.nowUsed; |
| 306 | } |
| 307 | p = (void*)pInt; |
| 308 | } |
| 309 | sqlite3_mutex_leave(mem.mutex); |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 310 | } |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 311 | return p; |
| 312 | } |
| 313 | |
| 314 | /* |
| 315 | ** Free memory. |
| 316 | */ |
| 317 | void sqlite3_free(void *pPrior){ |
| 318 | struct MemBlockHdr *pHdr; |
| 319 | void **pBt; |
drh | 4a50aac | 2007-08-23 02:47:53 +0000 | [diff] [blame] | 320 | char *z; |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 321 | if( pPrior==0 ){ |
| 322 | return; |
| 323 | } |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 324 | assert( mem.mutex!=0 ); |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 325 | pHdr = sqlite3MemsysGetHeader(pPrior); |
| 326 | pBt = (void**)pHdr; |
| 327 | pBt -= pHdr->nBacktraceSlots; |
drh | 6bdec4a | 2007-08-16 19:40:16 +0000 | [diff] [blame] | 328 | sqlite3_mutex_enter(mem.mutex); |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 329 | mem.nowUsed -= pHdr->iSize; |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 330 | if( pHdr->pPrev ){ |
| 331 | assert( pHdr->pPrev->pNext==pHdr ); |
| 332 | pHdr->pPrev->pNext = pHdr->pNext; |
| 333 | }else{ |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 334 | assert( mem.pFirst==pHdr ); |
| 335 | mem.pFirst = pHdr->pNext; |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 336 | } |
| 337 | if( pHdr->pNext ){ |
| 338 | assert( pHdr->pNext->pPrev==pHdr ); |
| 339 | pHdr->pNext->pPrev = pHdr->pPrev; |
| 340 | }else{ |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 341 | assert( mem.pLast==pHdr ); |
| 342 | mem.pLast = pHdr->pPrev; |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 343 | } |
drh | 4a50aac | 2007-08-23 02:47:53 +0000 | [diff] [blame] | 344 | z = (char*)pBt; |
| 345 | z -= pHdr->nTitle; |
| 346 | memset(z, 0x2b, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) + |
drh | 153c62c | 2007-08-24 03:51:33 +0000 | [diff] [blame] | 347 | pHdr->iSize + sizeof(int) + pHdr->nTitle); |
drh | 4a50aac | 2007-08-23 02:47:53 +0000 | [diff] [blame] | 348 | free(z); |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 349 | sqlite3_mutex_leave(mem.mutex); |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 350 | } |
| 351 | |
| 352 | /* |
| 353 | ** Change the size of an existing memory allocation. |
| 354 | ** |
| 355 | ** For this debugging implementation, we *always* make a copy of the |
| 356 | ** allocation into a new place in memory. In this way, if the |
| 357 | ** higher level code is using pointer to the old allocation, it is |
| 358 | ** much more likely to break and we are much more liking to find |
| 359 | ** the error. |
| 360 | */ |
drh | f3a65f7 | 2007-08-22 20:18:21 +0000 | [diff] [blame] | 361 | void *sqlite3_realloc(void *pPrior, int nByte){ |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 362 | struct MemBlockHdr *pOldHdr; |
| 363 | void *pNew; |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 364 | if( pPrior==0 ){ |
| 365 | return sqlite3_malloc(nByte); |
| 366 | } |
drh | f3a65f7 | 2007-08-22 20:18:21 +0000 | [diff] [blame] | 367 | if( nByte<=0 ){ |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 368 | sqlite3_free(pPrior); |
drh | 2f999a6 | 2007-08-15 19:16:43 +0000 | [diff] [blame] | 369 | return 0; |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 370 | } |
drh | d677b3d | 2007-08-20 22:48:41 +0000 | [diff] [blame] | 371 | assert( mem.disallow==0 ); |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 372 | pOldHdr = sqlite3MemsysGetHeader(pPrior); |
| 373 | pNew = sqlite3_malloc(nByte); |
| 374 | if( pNew ){ |
| 375 | memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize); |
| 376 | if( nByte>pOldHdr->iSize ){ |
| 377 | memset(&((char*)pNew)[pOldHdr->iSize], 0x2b, nByte - pOldHdr->iSize); |
| 378 | } |
| 379 | sqlite3_free(pPrior); |
| 380 | } |
| 381 | return pNew; |
| 382 | } |
| 383 | |
| 384 | /* |
| 385 | ** Set the number of backtrace levels kept for each allocation. |
| 386 | ** A value of zero turns of backtracing. The number is always rounded |
| 387 | ** up to a multiple of 2. |
| 388 | */ |
drh | 49e4fd7 | 2008-02-19 15:15:15 +0000 | [diff] [blame] | 389 | void sqlite3MemdebugBacktrace(int depth){ |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 390 | if( depth<0 ){ depth = 0; } |
| 391 | if( depth>20 ){ depth = 20; } |
drh | 2f999a6 | 2007-08-15 19:16:43 +0000 | [diff] [blame] | 392 | depth = (depth+1)&0xfe; |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 393 | mem.nBacktrace = depth; |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 394 | } |
| 395 | |
danielk1977 | 6f332c1 | 2008-03-21 14:22:44 +0000 | [diff] [blame] | 396 | void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){ |
| 397 | mem.xBacktrace = xBacktrace; |
| 398 | } |
| 399 | |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 400 | /* |
drh | 4a50aac | 2007-08-23 02:47:53 +0000 | [diff] [blame] | 401 | ** Set the title string for subsequent allocations. |
| 402 | */ |
drh | 49e4fd7 | 2008-02-19 15:15:15 +0000 | [diff] [blame] | 403 | void sqlite3MemdebugSettitle(const char *zTitle){ |
drh | 4a50aac | 2007-08-23 02:47:53 +0000 | [diff] [blame] | 404 | int n = strlen(zTitle) + 1; |
danielk1977 | ca0c897 | 2007-09-01 09:02:53 +0000 | [diff] [blame] | 405 | enterMem(); |
drh | 4a50aac | 2007-08-23 02:47:53 +0000 | [diff] [blame] | 406 | if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1; |
| 407 | memcpy(mem.zTitle, zTitle, n); |
| 408 | mem.zTitle[n] = 0; |
| 409 | mem.nTitle = (n+3)&~3; |
| 410 | sqlite3_mutex_leave(mem.mutex); |
| 411 | } |
| 412 | |
| 413 | /* |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 414 | ** Open the file indicated and write a log of all unfreed memory |
| 415 | ** allocations into that log. |
| 416 | */ |
drh | 49e4fd7 | 2008-02-19 15:15:15 +0000 | [diff] [blame] | 417 | void sqlite3MemdebugDump(const char *zFilename){ |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 418 | FILE *out; |
| 419 | struct MemBlockHdr *pHdr; |
| 420 | void **pBt; |
drh | d2bb327 | 2007-10-15 19:34:32 +0000 | [diff] [blame] | 421 | int i; |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 422 | out = fopen(zFilename, "w"); |
| 423 | if( out==0 ){ |
| 424 | fprintf(stderr, "** Unable to output memory debug output log: %s **\n", |
| 425 | zFilename); |
| 426 | return; |
| 427 | } |
drh | 0e6f154 | 2007-08-15 20:41:28 +0000 | [diff] [blame] | 428 | for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ |
drh | 4a50aac | 2007-08-23 02:47:53 +0000 | [diff] [blame] | 429 | char *z = (char*)pHdr; |
| 430 | z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle; |
drh | d5499d6 | 2007-08-24 04:15:00 +0000 | [diff] [blame] | 431 | fprintf(out, "**** %d bytes at %p from %s ****\n", |
| 432 | pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???"); |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 433 | if( pHdr->nBacktrace ){ |
| 434 | fflush(out); |
| 435 | pBt = (void**)pHdr; |
| 436 | pBt -= pHdr->nBacktraceSlots; |
| 437 | backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out)); |
| 438 | fprintf(out, "\n"); |
| 439 | } |
| 440 | } |
drh | d2bb327 | 2007-10-15 19:34:32 +0000 | [diff] [blame] | 441 | fprintf(out, "COUNTS:\n"); |
| 442 | for(i=0; i<NCSIZE-1; i++){ |
| 443 | if( mem.sizeCnt[i] ){ |
| 444 | fprintf(out, " %3d: %d\n", i*8+8, mem.sizeCnt[i]); |
| 445 | } |
| 446 | } |
| 447 | if( mem.sizeCnt[NCSIZE-1] ){ |
| 448 | fprintf(out, " >%3d: %d\n", NCSIZE*8, mem.sizeCnt[NCSIZE-1]); |
| 449 | } |
drh | 4c3645c | 2007-08-15 17:07:57 +0000 | [diff] [blame] | 450 | fclose(out); |
| 451 | } |
| 452 | |
danielk1977 | a7a8e14 | 2008-02-13 18:25:27 +0000 | [diff] [blame] | 453 | /* |
| 454 | ** Return the number of times sqlite3_malloc() has been called. |
| 455 | */ |
drh | 49e4fd7 | 2008-02-19 15:15:15 +0000 | [diff] [blame] | 456 | int sqlite3MemdebugMallocCount(){ |
danielk1977 | a7a8e14 | 2008-02-13 18:25:27 +0000 | [diff] [blame] | 457 | int i; |
| 458 | int nTotal = 0; |
| 459 | for(i=0; i<NCSIZE; i++){ |
| 460 | nTotal += mem.sizeCnt[i]; |
| 461 | } |
| 462 | return nTotal; |
| 463 | } |
| 464 | |
drh | d677b3d | 2007-08-20 22:48:41 +0000 | [diff] [blame] | 465 | |
drh | 0d18020 | 2008-02-14 23:26:56 +0000 | [diff] [blame] | 466 | #endif /* SQLITE_MEMDEBUG */ |