11#include <dispatch/dispatch.h>
32 fprintf(stderr,
"%s\n", message);
44 void *compositionState = NULL;
54#ifdef VUOHEAP_TRACEALL
58static bool VuoHeap_isComposition(
void)
60 static bool isComposition =
false;
61 static dispatch_once_t once = 0;
62 dispatch_once(&once, ^{
63 isComposition = dlsym(RTLD_DEFAULT,
"vuoCompositionStateKey");
101 if ((
unsigned long)pointer & 0xf)
108 if ((
unsigned long)pointer < 0x100000000)
115 if ((
unsigned long)pointer > 0xffffffffffff)
131 int pageSize = getpagesize();
132 long heapPageMask = ~((long)pageSize-1);
133 long heapPage = (long)pointer & heapPageMask;
136 mlock((
void *)heapPage, pageSize);
137 munlock((
void *)heapPage, pageSize);
141 if (mincore((
void *)heapPage, pageSize, pageStatus) == 0)
142 return pageStatus[0] & MINCORE_INCORE;
157 char *pointerAsChar = (
char *)pointer;
158 for (
int i = 0; i < 16; ++i)
159 if (isprint(pointerAsChar[i]))
160 summary[i] = pointerAsChar[i];
166 strlcpy(summary,
"(not allocated)", 17);
178 const char *format =
"%s:%d :: %s() :: %s";
179 int size = snprintf(NULL, 0, format, e.file, e.line, e.function, e.variable);
180 char *description = (
char *)malloc(size+1);
181 snprintf(description, size+1, format, e.file, e.line, e.function, e.variable);
190static void __attribute__((constructor(101))) VuoHeap_init()
198 const double dumpInterval = 5.0;
199 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
200 dispatch_source_set_timer(timer, dispatch_walltime(NULL,0), NSEC_PER_SEC*dumpInterval, NSEC_PER_SEC*dumpInterval);
201 dispatch_source_set_event_handler(timer, ^{
202 fprintf(stderr,
"\n\n\n\n\nreferenceCounts:\n");
206 const void *heapPointer = i->first;
207 char pointerSummary[17];
210 fprintf(stderr,
"\t% 3d refs to %p \"%s\", registered at %s\n", i->second.referenceCount, heapPointer, pointerSummary, description);
215 dispatch_resume(timer);
228 ostringstream errorMessage;
230 <<
", VuoRelease was not called enough times for:" << endl;
233 const void *heapPointer = i->first;
234 char pointerSummary[17];
237 errorMessage <<
"\t" << setw(3) << i->second.referenceCount <<
" refs to " << heapPointer <<
" \"" << pointerSummary <<
"\", registered at " << description << endl;
268 ostringstream errorMessage;
271 <<
", VuoRegister was called for bogus pointer " << heapPointer
272 <<
" " << description;
277 bool isAlreadyReferenceCounted;
283#ifdef VUOHEAP_TRACEALL
284 if (VuoHeap_isComposition())
289 fprintf(stderr,
"table=%p VuoRegister(%p) %s\n",
referenceCounts, heapPointer, pointerName);
295 if (! isAlreadyReferenceCounted)
298 (*referenceCounts)[heapPointer] = (
VuoHeapEntry){updatedCount, deallocate, file, linenumber, func, pointerName};
301 updatedCount = (*referenceCounts)[heapPointer].referenceCount;
305 if (isAlreadyReferenceCounted)
307 ostringstream errorMessage;
310 <<
", VuoRegister was called more than once for " << heapPointer
311 <<
" " << description;
323int VuoRegisterSingletonF(
const void *heapPointer,
const char *file,
unsigned int linenumber,
const char *func,
const char *pointerName)
330 ostringstream errorMessage;
333 <<
", VuoRegisterSingleton was called for bogus pointer " << heapPointer
334 <<
" " << description;
339 bool isAlreadyReferenceCounted;
344#ifdef VUOHEAP_TRACEALL
345 if (VuoHeap_isComposition())
350 fprintf(stderr,
"table=%p VuoRegisterSingleton(%p) %s\n",
referenceCounts, heapPointer, pointerName);
361 if (! isAlreadyReferenceCounted)
366 if (isAlreadyReferenceCounted)
368 ostringstream errorMessage;
371 <<
", VuoRegisterSingleton was called more than once for " << heapPointer
372 <<
" " << description;
377 return isAlreadyReferenceCounted ? 1 : 0;
388extern "C" int VuoRetainF(
const void *heapPointer,
const char *file,
unsigned int linenumber,
const char *func)
407 char pointerSummary[17];
409 ostringstream errorMessage;
411 <<
", VuoRetain was called for bogus pointer " << heapPointer
412 <<
" \"" << pointerSummary <<
"\"";
416 int updatedCount = -1;
417 bool foundSingleton =
false;
421 map<const void *, VuoHeapEntry>::iterator i =
referenceCounts->find(heapPointer);
424#ifdef VUOHEAP_TRACEALL
425 if (VuoHeap_isComposition())
436 updatedCount = ++(i->second.referenceCount);
442 if (updatedCount == -1 && !foundSingleton)
444 char pointerSummary[17];
446 ostringstream errorMessage;
448 <<
", VuoRetain was called for unregistered pointer " << heapPointer
449 <<
" \"" << pointerSummary <<
"\"";
464extern "C" int VuoReleaseF(
const void *heapPointer,
const char *file,
unsigned int linenumber,
const char *func)
484 char pointerSummary[17];
486 ostringstream errorMessage;
488 <<
", VuoRelease was called for bogus pointer " << heapPointer
489 <<
" \"" << pointerSummary <<
"\"";
493 int updatedCount = -1;
494 bool foundSingleton =
false;
495 bool isRegisteredWithoutRetain =
false;
500 map<const void *, VuoHeapEntry>::iterator i =
referenceCounts->find(heapPointer);
503#ifdef VUOHEAP_TRACEALL
504 if (VuoHeap_isComposition())
516 if (i->second.referenceCount == 0)
518 isRegisteredWithoutRetain =
true;
522 updatedCount = --(i->second.referenceCount);
524 if (updatedCount == 0)
526 deallocate = i->second.deallocateFunction;
535 if (updatedCount == 0)
537#ifdef VUOHEAP_TRACEALL
538 if (VuoHeap_isComposition())
545 fprintf(stderr,
"table=%p VuoDeallocate(%p)\n",
referenceCounts, heapPointer);
553 if (updatedCount == 0)
554 deallocate((
void *)heapPointer);
555 else if (updatedCount == -1 && !foundSingleton)
557 char pointerSummary[17];
559 ostringstream errorMessage;
561 <<
", VuoRelease was called for "
562 << (isRegisteredWithoutRetain ?
"unretained" :
"unregistered")
563 <<
" pointer " << heapPointer
564 <<
" \"" << pointerSummary <<
"\"";
580 char *description =
nullptr;
584 map<const void *, VuoHeapEntry>::iterator i =
referenceCounts->find(heapPointer);
593 return strdup(
"(pointer was not VuoRegister()ed)");