00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "memoryHook.h"
00016 #include "deletedBufferChain.h"
00017 #include <stdlib.h>
00018
00019 #ifdef WIN32
00020
00021
00022 #define WIN32_LEAN_AND_MEAN
00023 #include <windows.h>
00024
00025 #else
00026
00027
00028 #include <unistd.h>
00029 #include <sys/types.h>
00030 #include <sys/mman.h>
00031
00032 #ifndef MAP_ANON
00033 #define MAP_ANON 0x1000
00034 #endif
00035
00036 #endif // WIN32
00037
00038
00039 #if defined(USE_MEMORY_DLMALLOC)
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #define USE_DL_PREFIX 1
00051 #define NO_MALLINFO 1
00052 #ifdef _DEBUG
00053 #define DEBUG 1
00054 #endif
00055 #include "dlmalloc.h"
00056 #include "dlmalloc_src.cxx"
00057
00058 #define call_malloc dlmalloc
00059 #define call_realloc dlrealloc
00060 #define call_free dlfree
00061 #define MEMORY_HOOK_MALLOC_LOCK 1
00062
00063 #elif defined(USE_MEMORY_PTMALLOC2)
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 #define USE_DL_PREFIX 1
00081 #define NO_MALLINFO 1
00082 #ifdef _DEBUG
00083 #define MALLOC_DEBUG 2
00084 #endif
00085 #include "ptmalloc2_smp_src.cxx"
00086
00087 #define call_malloc dlmalloc
00088 #define call_realloc dlrealloc
00089 #define call_free dlfree
00090 #undef MEMORY_HOOK_MALLOC_LOCK
00091
00092 #else
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 #define call_malloc malloc
00104 #define call_realloc realloc
00105 #define call_free free
00106 #undef MEMORY_HOOK_MALLOC_LOCK
00107
00108 #endif // USE_MEMORY_*
00109
00110
00111
00112
00113
00114
00115 MemoryHook::
00116 MemoryHook() {
00117 #ifdef WIN32
00118
00119
00120 SYSTEM_INFO sysinfo;
00121 GetSystemInfo(&sysinfo);
00122
00123 _page_size = (size_t)sysinfo.dwPageSize;
00124
00125 #else
00126
00127
00128 _page_size = sysconf(_SC_PAGESIZE);
00129
00130 #endif // WIN32
00131
00132 #ifdef DO_MEMORY_USAGE
00133 _total_heap_single_size = 0;
00134 _total_heap_array_size = 0;
00135 _requested_heap_size = 0;
00136 _total_mmap_size = 0;
00137 _max_heap_size = ~(size_t)0;
00138 #endif
00139 }
00140
00141
00142
00143
00144
00145
00146 MemoryHook::
00147 MemoryHook(const MemoryHook ©) :
00148 _page_size(copy._page_size)
00149 {
00150 #ifdef DO_MEMORY_USAGE
00151 _total_heap_single_size = copy._total_heap_single_size;
00152 _total_heap_array_size = copy._total_heap_array_size;
00153 _requested_heap_size = copy._requested_heap_size;
00154 _total_mmap_size = copy._total_mmap_size;
00155 _max_heap_size = copy._max_heap_size;
00156 #endif
00157
00158 ((MutexImpl &)copy._lock).acquire();
00159 _deleted_chains = copy._deleted_chains;
00160 ((MutexImpl &)copy._lock).release();
00161 }
00162
00163
00164
00165
00166
00167
00168 MemoryHook::
00169 ~MemoryHook() {
00170
00171
00172 }
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 void *MemoryHook::
00186 heap_alloc_single(size_t size) {
00187 size_t inflated_size = inflate_size(size);
00188
00189 #ifdef MEMORY_HOOK_MALLOC_LOCK
00190 _lock.acquire();
00191 void *alloc = call_malloc(inflated_size);
00192 _lock.release();
00193 #else
00194 void *alloc = call_malloc(inflated_size);
00195 #endif
00196
00197 while (alloc == (void *)NULL) {
00198 alloc_fail(inflated_size);
00199 #ifdef MEMORY_HOOK_MALLOC_LOCK
00200 _lock.acquire();
00201 alloc = call_malloc(inflated_size);
00202 _lock.release();
00203 #else
00204 alloc = call_malloc(inflated_size);
00205 #endif
00206 }
00207
00208 #ifdef DO_MEMORY_USAGE
00209
00210
00211 AtomicAdjust::add(_total_heap_single_size, (AtomicAdjust::Integer)size);
00212 if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
00213 (size_t)AtomicAdjust::get(_total_heap_array_size) >
00214 _max_heap_size) {
00215 overflow_heap_size();
00216 }
00217 #endif // DO_MEMORY_USAGE
00218
00219 void *ptr = alloc_to_ptr(alloc, size);
00220 assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
00221 return ptr;
00222 }
00223
00224
00225
00226
00227
00228
00229
00230 void MemoryHook::
00231 heap_free_single(void *ptr) {
00232 size_t size;
00233 void *alloc = ptr_to_alloc(ptr, size);
00234
00235 #ifdef DO_MEMORY_USAGE
00236 assert((int)size <= _total_heap_single_size);
00237 AtomicAdjust::add(_total_heap_single_size, -(AtomicAdjust::Integer)size);
00238 #endif // DO_MEMORY_USAGE
00239
00240 #ifdef MEMORY_HOOK_MALLOC_LOCK
00241 _lock.acquire();
00242 call_free(alloc);
00243 _lock.release();
00244 #else
00245 call_free(alloc);
00246 #endif
00247 }
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 void *MemoryHook::
00262 heap_alloc_array(size_t size) {
00263 size_t inflated_size = inflate_size(size);
00264
00265 #ifdef MEMORY_HOOK_MALLOC_LOCK
00266 _lock.acquire();
00267 void *alloc = call_malloc(inflated_size);
00268 _lock.release();
00269 #else
00270 void *alloc = call_malloc(inflated_size);
00271 #endif
00272
00273 while (alloc == (void *)NULL) {
00274 alloc_fail(inflated_size);
00275 #ifdef MEMORY_HOOK_MALLOC_LOCK
00276 _lock.acquire();
00277 alloc = call_malloc(inflated_size);
00278 _lock.release();
00279 #else
00280 alloc = call_malloc(inflated_size);
00281 #endif
00282 }
00283
00284 #ifdef DO_MEMORY_USAGE
00285
00286
00287 AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size);
00288 if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
00289 (size_t)AtomicAdjust::get(_total_heap_array_size) >
00290 _max_heap_size) {
00291 overflow_heap_size();
00292 }
00293 #endif // DO_MEMORY_USAGE
00294
00295 void *ptr = alloc_to_ptr(alloc, size);
00296 assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
00297 return ptr;
00298 }
00299
00300
00301
00302
00303
00304
00305
00306 void *MemoryHook::
00307 heap_realloc_array(void *ptr, size_t size) {
00308 size_t orig_size;
00309 void *alloc = ptr_to_alloc(ptr, orig_size);
00310
00311 #ifdef DO_MEMORY_USAGE
00312 assert((AtomicAdjust::Integer)orig_size <= _total_heap_array_size);
00313 AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size-(AtomicAdjust::Integer)orig_size);
00314 #endif // DO_MEMORY_USAGE
00315
00316 size_t inflated_size = inflate_size(size);
00317
00318 void *alloc1 = alloc;
00319 #ifdef MEMORY_HOOK_MALLOC_LOCK
00320 _lock.acquire();
00321 alloc1 = call_realloc(alloc1, inflated_size);
00322 _lock.release();
00323 #else
00324 alloc1 = call_realloc(alloc1, inflated_size);
00325 #endif
00326
00327 while (alloc1 == (void *)NULL) {
00328 alloc_fail(inflated_size);
00329
00330
00331 alloc1 = alloc;
00332
00333 #ifdef MEMORY_HOOK_MALLOC_LOCK
00334 _lock.acquire();
00335 alloc1 = call_realloc(alloc1, inflated_size);
00336 _lock.release();
00337 #else
00338 alloc1 = call_realloc(alloc1, inflated_size);
00339 #endif
00340 }
00341
00342 void *ptr1 = alloc_to_ptr(alloc1, size);
00343 assert(ptr1 >= alloc1 && (char *)ptr1 + size <= (char *)alloc1 + inflated_size);
00344 #if defined(MEMORY_HOOK_DO_ALIGN)
00345
00346
00347 size_t orig_delta = (char *)ptr - (char *)alloc;
00348 size_t new_delta = (char *)ptr1 - (char *)alloc1;
00349 if (orig_delta != new_delta) {
00350 memmove((char *)alloc1 + new_delta, (char *)alloc1 + orig_delta, min(size, orig_size));
00351 }
00352 #endif // MEMORY_HOOK_DO_ALIGN
00353 return ptr1;
00354 }
00355
00356
00357
00358
00359
00360
00361
00362 void MemoryHook::
00363 heap_free_array(void *ptr) {
00364 size_t size;
00365 void *alloc = ptr_to_alloc(ptr, size);
00366
00367 #ifdef DO_MEMORY_USAGE
00368 assert((int)size <= _total_heap_array_size);
00369 AtomicAdjust::add(_total_heap_array_size, -(AtomicAdjust::Integer)size);
00370 #endif // DO_MEMORY_USAGE
00371
00372 #ifdef MEMORY_HOOK_MALLOC_LOCK
00373 _lock.acquire();
00374 call_free(alloc);
00375 _lock.release();
00376 #else
00377 call_free(alloc);
00378 #endif
00379 }
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 bool MemoryHook::
00396 heap_trim(size_t pad) {
00397 bool trimmed = false;
00398
00399 #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
00400
00401
00402
00403 _lock.acquire();
00404 if (dlmalloc_trim(pad)) {
00405 trimmed = true;
00406 }
00407 _lock.release();
00408 #endif
00409
00410 #ifdef WIN32
00411
00412 if (_heapmin() == 0) {
00413 trimmed = true;
00414 }
00415 #endif
00416
00417 return trimmed;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436 void *MemoryHook::
00437 mmap_alloc(size_t size, bool allow_exec) {
00438 assert((size % _page_size) == 0);
00439
00440 #ifdef DO_MEMORY_USAGE
00441 _total_mmap_size += size;
00442 #endif
00443
00444 #ifdef WIN32
00445
00446
00447 void *ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE,
00448 allow_exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
00449 if (ptr == (void *)NULL) {
00450 DWORD err = GetLastError();
00451 cerr << "Couldn't allocate memory page of size " << size << ": ";
00452
00453 PVOID buffer;
00454 DWORD length =
00455 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00456 NULL, err, 0, (LPTSTR)&buffer, 0, NULL);
00457 if (length != 0) {
00458 cerr << (char *)buffer << "\n";
00459 } else {
00460 cerr << "Error code " << err << "\n";
00461 }
00462 LocalFree(buffer);
00463 abort();
00464 }
00465
00466 return ptr;
00467
00468 #else
00469
00470
00471 int prot = PROT_READ | PROT_WRITE;
00472 if (allow_exec) {
00473 prot |= PROT_EXEC;
00474 }
00475 void *ptr = mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
00476 if (ptr == (void *)-1) {
00477 perror("mmap");
00478 abort();
00479 }
00480
00481 return ptr;
00482
00483 #endif // WIN32
00484 }
00485
00486
00487
00488
00489
00490
00491
00492 void MemoryHook::
00493 mmap_free(void *ptr, size_t size) {
00494 assert((size % _page_size) == 0);
00495
00496 #ifdef DO_MEMORY_USAGE
00497 assert((int)size <= _total_mmap_size);
00498 _total_mmap_size -= size;
00499 #endif
00500
00501 #ifdef WIN32
00502 VirtualFree(ptr, 0, MEM_RELEASE);
00503 #else
00504 munmap(ptr, size);
00505 #endif
00506 }
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 void MemoryHook::
00520 mark_pointer(void *, size_t, ReferenceCount *) {
00521 }
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531 DeletedBufferChain *MemoryHook::
00532 get_deleted_chain(size_t buffer_size) {
00533 DeletedBufferChain *chain;
00534
00535 _lock.acquire();
00536 DeletedChains::iterator dci = _deleted_chains.find(buffer_size);
00537 if (dci != _deleted_chains.end()) {
00538 chain = (*dci).second;
00539 } else {
00540
00541 chain = new DeletedBufferChain(buffer_size);
00542 _deleted_chains.insert(DeletedChains::value_type(buffer_size, chain));
00543 }
00544
00545 _lock.release();
00546 return chain;
00547 }
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 void MemoryHook::
00567 alloc_fail(size_t attempted_size) {
00568 cerr << "Out of memory allocating " << attempted_size << " bytes\n";
00569 abort();
00570 }
00571
00572 #ifdef DO_MEMORY_USAGE
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584 void MemoryHook::
00585 overflow_heap_size() {
00586 _max_heap_size = ~(size_t)0;
00587 }
00588 #endif // DO_MEMORY_USAGE