static void heaptracker_free_leaked_memory(void) { struct hdr *del; int cnt; if (num) log_message("+++ THERE ARE %d LEAKED ALLOCATIONS\n", num); while (head) { int safe; del = head; log_message("+++ DELETING %d BYTES OF LEAKED MEMORY AT %p (%d REMAINING)\n", del->size, user(del), num); if (del_leak(del, &safe)) { /* safe == 1, because the allocation is valid */ log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", user(del), del->size); print_backtrace(del->bt, del->bt_depth); } dlfree(del); } // log_message("+++ DELETING %d BACKLOGGED ALLOCATIONS\n", backlog_num); while (backlog_head) { del = backlog_tail; del_from_backlog(del); dlfree(del); } }
static void ReportMemoryLeaks() { ScopedDisableDebugCalls disable; // Use /proc/self/exe link to obtain the program name for logging // purposes. If it's not available, we set it to "<unknown>". char exe[PATH_MAX]; int count; if ((count = readlink("/proc/self/exe", exe, sizeof(exe) - 1)) == -1) { strlcpy(exe, "<unknown>", sizeof(exe)); } else { exe[count] = '\0'; } if (g_allocated_block_count == 0) { log_message("+++ %s did not leak", exe); return; } size_t index = 1; const size_t total = g_allocated_block_count; while (head != NULL) { int safe; hdr_t* block = head; log_message("+++ %s leaked block of size %d at %p (leak %d of %d)", exe, block->size, user(block), index++, total); if (del_leak(block, &safe) && g_backtrace_enabled) { /* safe == 1, because the allocation is valid */ log_backtrace(block->bt, block->bt_depth); } } while (backlog_head != NULL) { del_from_backlog(backlog_tail); } }
void *chk_realloc(void *ptr, size_t size) { struct hdr *hdr; // log_message("%s: %s\n", __FILE__, __FUNCTION__); if (!size) { chk_free(ptr); return NULL; } if (!ptr) return chk_malloc(size); hdr = meta(ptr); if (del(hdr) < 0) { intptr_t bt[MAX_BACKTRACE_DEPTH]; int depth; depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH); if (hdr->tag == BACKLOG_TAG) { log_message("+++ REALLOCATION %p SIZE %d OF FREED MEMORY!\n", user(hdr), size, hdr->size); log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", user(hdr), hdr->size); print_backtrace(hdr->bt, hdr->bt_depth); /* hdr->freed_bt_depth should be nonzero here */ log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n", user(hdr), hdr->size); print_backtrace(hdr->freed_bt, hdr->freed_bt_depth); log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n", user(hdr), hdr->size); print_backtrace(bt, depth); /* We take the memory out of the backlog and fall through so the * reallocation below succeeds. Since we didn't really free it, we * can default to this behavior. */ del_from_backlog(hdr); } else { log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n", user(hdr), size); print_backtrace(bt, depth); // just get a whole new allocation and leak the old one return dlrealloc(0, size); // return dlrealloc(user(hdr), size); // assuming it was allocated externally } } hdr = dlrealloc(hdr, sizeof(struct hdr) + size + sizeof(struct ftr)); if (hdr) { hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH); add(hdr, size); return user(hdr); } return NULL; }
extern "C" void* chk_realloc(void* ptr, size_t size) { // log_message("%s: %s\n", __FILE__, __FUNCTION__); if (!ptr) { return chk_malloc(size); } #ifdef REALLOC_ZERO_BYTES_FREE if (!size) { chk_free(ptr); return NULL; } #endif hdr_t* hdr = meta(ptr); if (del(hdr) < 0) { uintptr_t bt[MAX_BACKTRACE_DEPTH]; int depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH); if (hdr->tag == BACKLOG_TAG) { log_message("+++ REALLOCATION %p SIZE %d OF FREED MEMORY!\n", user(hdr), size, hdr->size); log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", user(hdr), hdr->size); log_backtrace(hdr->bt, hdr->bt_depth); /* hdr->freed_bt_depth should be nonzero here */ log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n", user(hdr), hdr->size); log_backtrace(hdr->freed_bt, hdr->freed_bt_depth); log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n", user(hdr), hdr->size); log_backtrace(bt, depth); /* We take the memory out of the backlog and fall through so the * reallocation below succeeds. Since we didn't really free it, we * can default to this behavior. */ del_from_backlog(hdr); } else { log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n", user(hdr), size); log_backtrace(bt, depth); // just get a whole new allocation and leak the old one return dlrealloc(0, size); // return dlrealloc(user(hdr), size); // assuming it was allocated externally } } if (hdr->base != hdr) { // An allocation from memalign, so create another allocation and // copy the data out. void* newMem = dlmalloc(sizeof(hdr_t) + size + sizeof(ftr_t)); if (newMem) { memcpy(newMem, hdr, sizeof(hdr_t) + hdr->size); dlfree(hdr->base); hdr = static_cast<hdr_t*>(newMem); } else { dlfree(hdr->base); hdr = NULL; } } else { hdr = static_cast<hdr_t*>(dlrealloc(hdr, sizeof(hdr_t) + size + sizeof(ftr_t))); } if (hdr) { hdr->base = hdr; hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH); add(hdr, size); return user(hdr); } return NULL; }