1e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev/* 2e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * Copyright (C) 2012 The Android Open Source Project 3e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * All rights reserved. 4e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * 5e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * Redistribution and use in source and binary forms, with or without 6e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * modification, are permitted provided that the following conditions 7e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * are met: 8e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * * Redistributions of source code must retain the above copyright 9e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * notice, this list of conditions and the following disclaimer. 10e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * * Redistributions in binary form must reproduce the above copyright 11e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * notice, this list of conditions and the following disclaimer in 12e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * the documentation and/or other materials provided with the 13e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * distribution. 14e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * 15e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * SUCH DAMAGE. 27e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev */ 28e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <arpa/inet.h> 303b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <dlfcn.h> 31e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#include <errno.h> 323b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <errno.h> 333b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <fcntl.h> 34e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#include <pthread.h> 353b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <stdarg.h> 363b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <stdbool.h> 373b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <stddef.h> 38e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#include <stdio.h> 39e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#include <stdlib.h> 40e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#include <string.h> 413b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <sys/socket.h> 423b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <sys/system_properties.h> 433b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <sys/types.h> 443b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include <time.h> 45e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#include <unistd.h> 46e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#include <unwind.h> 47e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 481e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#include "debug_mapinfo.h" 491e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#include "debug_stacktrace.h" 50e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#include "dlmalloc.h" 518f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes#include "libc_logging.h" 523b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include "malloc_debug_common.h" 533b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#include "ScopedPthreadMutexLocker.h" 54e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 55e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev/* libc.debug.malloc.backlog */ 569c81892c2e8c684e0da12028e389bf6d9b5253b7Elliott Hughesextern unsigned int gMallocDebugBacklog; 579c81892c2e8c684e0da12028e389bf6d9b5253b7Elliott Hughesextern int gMallocDebugLevel; 58e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 591e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#define MAX_BACKTRACE_DEPTH 16 60e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#define ALLOCATION_TAG 0x1ee7d00d 61e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#define BACKLOG_TAG 0xbabecafe 62e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#define FREE_POISON 0xa5 63e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#define FRONT_GUARD 0xaa 64e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#define FRONT_GUARD_LEN (1<<5) 65e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#define REAR_GUARD 0xbb 66e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev#define REAR_GUARD_LEN (1<<5) 67e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 68c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstatic void log_message(const char* format, ...) { 691e980b6bc8315d00a07312b25486531247abd98cElliott Hughes va_list args; 701e980b6bc8315d00a07312b25486531247abd98cElliott Hughes va_start(args, format); 711e980b6bc8315d00a07312b25486531247abd98cElliott Hughes __libc_format_log_va_list(ANDROID_LOG_ERROR, "libc", format, args); 721e980b6bc8315d00a07312b25486531247abd98cElliott Hughes va_end(args); 73e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 74e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 75c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstruct hdr_t { 76e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev uint32_t tag; 773d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris void* base; // Always points to the memory allocated using dlmalloc. 783d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // For memory allocated in chk_memalign, this value will 793d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // not be the same as the location of the start of this 803d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // structure. 81c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes hdr_t* prev; 82c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes hdr_t* next; 83239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes uintptr_t bt[MAX_BACKTRACE_DEPTH]; 84e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev int bt_depth; 85239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes uintptr_t freed_bt[MAX_BACKTRACE_DEPTH]; 86e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev int freed_bt_depth; 87e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev size_t size; 88e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev char front_guard[FRONT_GUARD_LEN]; 893d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris} __attribute__((packed, aligned(MALLOC_ALIGNMENT))); 90e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 91c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstruct ftr_t { 92e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev char rear_guard[REAR_GUARD_LEN]; 93e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} __attribute__((packed)); 94e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 95c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstatic inline ftr_t* to_ftr(hdr_t* hdr) { 96c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes return reinterpret_cast<ftr_t*>(reinterpret_cast<char*>(hdr + 1) + hdr->size); 97e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 98e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 99c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstatic inline void* user(hdr_t* hdr) { 100e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return hdr + 1; 101e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 102e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 103c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstatic inline hdr_t* meta(void* user) { 104c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes return reinterpret_cast<hdr_t*>(user) - 1; 105e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 106e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 1073d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline const hdr_t* const_meta(const void* user) { 1083d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris return reinterpret_cast<const hdr_t*>(user) - 1; 1093d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris} 1103d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris 1113d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris 112239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughesstatic unsigned gAllocatedBlockCount; 1133d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic hdr_t* tail; 1143d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic hdr_t* head; 115e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchevstatic pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 116e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 117e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchevstatic unsigned backlog_num; 1183d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic hdr_t* backlog_tail; 1193d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic hdr_t* backlog_head; 120e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchevstatic pthread_mutex_t backlog_lock = PTHREAD_MUTEX_INITIALIZER; 121e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 1223d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline void init_front_guard(hdr_t* hdr) { 123e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev memset(hdr->front_guard, FRONT_GUARD, FRONT_GUARD_LEN); 124e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 125e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 1263d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline bool is_front_guard_valid(hdr_t* hdr) { 127c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes for (size_t i = 0; i < FRONT_GUARD_LEN; i++) { 128c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes if (hdr->front_guard[i] != FRONT_GUARD) { 129e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return 0; 130c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } 131c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } 132e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return 1; 133e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 134e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 1353d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline void init_rear_guard(hdr_t* hdr) { 136c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes ftr_t* ftr = to_ftr(hdr); 137e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev memset(ftr->rear_guard, REAR_GUARD, REAR_GUARD_LEN); 138e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 139e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 1403d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline bool is_rear_guard_valid(hdr_t* hdr) { 141e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev unsigned i; 142e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev int valid = 1; 143e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev int first_mismatch = -1; 144c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes ftr_t* ftr = to_ftr(hdr); 145e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev for (i = 0; i < REAR_GUARD_LEN; i++) { 146e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (ftr->rear_guard[i] != REAR_GUARD) { 147e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (first_mismatch < 0) 148e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev first_mismatch = i; 149e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev valid = 0; 150c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } else if (first_mismatch >= 0) { 151e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ REAR GUARD MISMATCH [%d, %d)\n", first_mismatch, i); 152e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev first_mismatch = -1; 153e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 154e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 155e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 156e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (first_mismatch >= 0) 157e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ REAR GUARD MISMATCH [%d, %d)\n", first_mismatch, i); 158e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return valid; 159e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 160e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 1613d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline void add_locked(hdr_t* hdr, hdr_t** tail, hdr_t** head) { 162e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev hdr->prev = NULL; 163e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev hdr->next = *head; 164e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (*head) 165e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev (*head)->prev = hdr; 166e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev else 167e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev *tail = hdr; 168e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev *head = hdr; 169e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 170e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 1713d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline int del_locked(hdr_t* hdr, hdr_t** tail, hdr_t** head) { 172c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes if (hdr->prev) { 173e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev hdr->prev->next = hdr->next; 174c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } else { 175e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev *head = hdr->next; 176c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } 177c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes if (hdr->next) { 178e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev hdr->next->prev = hdr->prev; 179c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } else { 180e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev *tail = hdr->prev; 181c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } 182e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return 0; 183e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 184e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 1853d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline void add(hdr_t* hdr, size_t size) { 186c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes ScopedPthreadMutexLocker locker(&lock); 187e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev hdr->tag = ALLOCATION_TAG; 188e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev hdr->size = size; 189e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev init_front_guard(hdr); 190e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev init_rear_guard(hdr); 191239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes ++gAllocatedBlockCount; 192e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev add_locked(hdr, &tail, &head); 193e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 194e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 1953d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline int del(hdr_t* hdr) { 196c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes if (hdr->tag != ALLOCATION_TAG) { 197e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return -1; 198c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } 199e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 200c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes ScopedPthreadMutexLocker locker(&lock); 201e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev del_locked(hdr, &tail, &head); 202239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes --gAllocatedBlockCount; 203e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return 0; 204e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 205e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 2063d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline void poison(hdr_t* hdr) { 207e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev memset(user(hdr), FREE_POISON, hdr->size); 208e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 209e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 2103d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic int was_used_after_free(hdr_t* hdr) { 211e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev unsigned i; 2123d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris const char* data = reinterpret_cast<const char *>(user(hdr)); 213e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev for (i = 0; i < hdr->size; i++) 214e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (data[i] != FREE_POISON) 215e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return 1; 216e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return 0; 217e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 218e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 219e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev/* returns 1 if valid, *safe == 1 if safe to dump stack */ 2203d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline int check_guards(hdr_t* hdr, int* safe) { 221e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev *safe = 1; 222e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (!is_front_guard_valid(hdr)) { 223e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (hdr->front_guard[0] == FRONT_GUARD) { 224e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d HAS A CORRUPTED FRONT GUARD\n", 225e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 226e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } else { 227e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p HAS A CORRUPTED FRONT GUARD "\ 228e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev "(NOT DUMPING STACKTRACE)\n", user(hdr)); 229e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev /* Allocation header is probably corrupt, do not print stack trace */ 230e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev *safe = 0; 231e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 232e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return 0; 233e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 234e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 235e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (!is_rear_guard_valid(hdr)) { 236e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d HAS A CORRUPTED REAR GUARD\n", 237e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 238e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return 0; 239e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 240e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 241e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return 1; 242e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 243e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 244e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev/* returns 1 if valid, *safe == 1 if safe to dump stack */ 2453d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline int check_allocation_locked(hdr_t* hdr, int* safe) { 246e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev int valid = 1; 247e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev *safe = 1; 248e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 249e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (hdr->tag != ALLOCATION_TAG && hdr->tag != BACKLOG_TAG) { 250e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p HAS INVALID TAG %08x (NOT DUMPING STACKTRACE)\n", 251e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->tag); 252c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes // Allocation header is probably corrupt, do not dequeue or dump stack 253c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes // trace. 254e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev *safe = 0; 255e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return 0; 256e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 257e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 258e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (hdr->tag == BACKLOG_TAG && was_used_after_free(hdr)) { 259e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d WAS USED AFTER BEING FREED\n", 260e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 261e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev valid = 0; 262c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes /* check the guards to see if it's safe to dump a stack trace */ 263c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes check_guards(hdr, safe); 264c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } else { 265e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev valid = check_guards(hdr, safe); 266c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } 267e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 268e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (!valid && *safe) { 269e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", 270e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 27135b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(hdr->bt, hdr->bt_depth); 272e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (hdr->tag == BACKLOG_TAG) { 273e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d FREED HERE:\n", 274e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 27535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(hdr->freed_bt, hdr->freed_bt_depth); 276e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 277e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 278e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 279e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return valid; 280e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 281e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 2823d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline int del_and_check_locked(hdr_t* hdr, 2833d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr_t** tail, hdr_t** head, unsigned* cnt, 2843d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris int* safe) { 285c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes int valid = check_allocation_locked(hdr, safe); 286e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (safe) { 287e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev (*cnt)--; 288e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev del_locked(hdr, tail, head); 289e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 290e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return valid; 291e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 292e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 2933d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline void del_from_backlog_locked(hdr_t* hdr) { 294c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes int safe; 295c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes del_and_check_locked(hdr, 296c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes &backlog_tail, &backlog_head, &backlog_num, 297c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes &safe); 298c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes hdr->tag = 0; /* clear the tag */ 299e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 300e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 3013d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline void del_from_backlog(hdr_t* hdr) { 302c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes ScopedPthreadMutexLocker locker(&backlog_lock); 303e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev del_from_backlog_locked(hdr); 304e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 305e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 3063d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline int del_leak(hdr_t* hdr, int* safe) { 307c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes ScopedPthreadMutexLocker locker(&lock); 308239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes return del_and_check_locked(hdr, &tail, &head, &gAllocatedBlockCount, safe); 309e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 310e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 3113d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisstatic inline void add_to_backlog(hdr_t* hdr) { 312c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes ScopedPthreadMutexLocker locker(&backlog_lock); 313e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev hdr->tag = BACKLOG_TAG; 314e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev backlog_num++; 315e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev add_locked(hdr, &backlog_tail, &backlog_head); 316e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev poison(hdr); 317e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev /* If we've exceeded the maximum backlog, clear it up */ 3189c81892c2e8c684e0da12028e389bf6d9b5253b7Elliott Hughes while (backlog_num > gMallocDebugBacklog) { 3193d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr_t* gone = backlog_tail; 320e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev del_from_backlog_locked(gone); 3213d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris dlfree(gone->base); 322e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 323e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 324e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 325c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void* chk_malloc(size_t size) { 326e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev// log_message("%s: %s\n", __FILE__, __FUNCTION__); 327e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 328c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes hdr_t* hdr = static_cast<hdr_t*>(dlmalloc(sizeof(hdr_t) + size + sizeof(ftr_t))); 329e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (hdr) { 3303d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr->base = hdr; 331e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH); 332e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev add(hdr, size); 333e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return user(hdr); 334e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 335e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return NULL; 336e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 337e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 3383d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisextern "C" void* chk_memalign(size_t alignment, size_t bytes) { 3393d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris if (alignment <= MALLOC_ALIGNMENT) { 3403d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris return chk_malloc(bytes); 3413d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris } 3423d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris 3433d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // Make the alignment a power of two. 3443d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris if (alignment & (alignment-1)) { 3453d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris alignment = 1L << (31 - __builtin_clz(alignment)); 3463d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris } 3473d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris 3483d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // here, alignment is at least MALLOC_ALIGNMENT<<1 bytes 3493d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // we will align by at least MALLOC_ALIGNMENT bytes 3503d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // and at most alignment-MALLOC_ALIGNMENT bytes 3513d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris size_t size = (alignment-MALLOC_ALIGNMENT) + bytes; 3523d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris if (size < bytes) { // Overflow. 3533d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris return NULL; 3543d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris } 3553d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris 3563d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris void* base = dlmalloc(sizeof(hdr_t) + size + sizeof(ftr_t)); 3573d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris if (base != NULL) { 3583d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // Check that the actual pointer that will be returned is aligned 3593d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // properly. 3603d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris uintptr_t ptr = reinterpret_cast<uintptr_t>(user(reinterpret_cast<hdr_t*>(base))); 3613d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris if ((ptr % alignment) != 0) { 3623d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // Align the pointer. 3633d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris ptr += ((-ptr) % alignment); 3643d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris } 3653d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris 3663d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr_t* hdr = meta(reinterpret_cast<void*>(ptr)); 3673d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr->base = base; 3683d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH); 3693d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris add(hdr, bytes); 3703d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris return user(hdr); 3713d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris } 3723d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris return base; 373e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 374e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 3753d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisextern "C" void chk_free(void* ptr) { 376e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev// log_message("%s: %s\n", __FILE__, __FUNCTION__); 377e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 378e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (!ptr) /* ignore free(NULL) */ 379e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return; 380e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 381c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes hdr_t* hdr = meta(ptr); 382e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 383e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (del(hdr) < 0) { 384239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes uintptr_t bt[MAX_BACKTRACE_DEPTH]; 38535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes int depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH); 386e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (hdr->tag == BACKLOG_TAG) { 387e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d BYTES MULTIPLY FREED!\n", 388e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 389e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", 390e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 39135b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(hdr->bt, hdr->bt_depth); 392e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev /* hdr->freed_bt_depth should be nonzero here */ 393e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n", 394e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 39535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(hdr->freed_bt, hdr->freed_bt_depth); 396e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d NOW BEING FREED HERE:\n", 397e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 39835b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(bt, depth); 399c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } else { 400e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n", 401e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr)); 40235b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(bt, depth); 403e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 404c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } else { 40535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes hdr->freed_bt_depth = get_backtrace(hdr->freed_bt, MAX_BACKTRACE_DEPTH); 406e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev add_to_backlog(hdr); 407e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 408e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 409e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 4103d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisextern "C" void* chk_realloc(void* ptr, size_t size) { 411e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev// log_message("%s: %s\n", __FILE__, __FUNCTION__); 412e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 413e7e274b13a44a63023f22630ac282ee2e919ffb7Elliott Hughes if (!ptr) { 414e7e274b13a44a63023f22630ac282ee2e919ffb7Elliott Hughes return chk_malloc(size); 415e7e274b13a44a63023f22630ac282ee2e919ffb7Elliott Hughes } 416e7e274b13a44a63023f22630ac282ee2e919ffb7Elliott Hughes 417e7e274b13a44a63023f22630ac282ee2e919ffb7Elliott Hughes#ifdef REALLOC_ZERO_BYTES_FREE 418e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (!size) { 419e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev chk_free(ptr); 420e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return NULL; 421e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 422e7e274b13a44a63023f22630ac282ee2e919ffb7Elliott Hughes#endif 423e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 424c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes hdr_t* hdr = meta(ptr); 425e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 426e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (del(hdr) < 0) { 427239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes uintptr_t bt[MAX_BACKTRACE_DEPTH]; 42835b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes int depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH); 429e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (hdr->tag == BACKLOG_TAG) { 430e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ REALLOCATION %p SIZE %d OF FREED MEMORY!\n", 431e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), size, hdr->size); 432e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", 433e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 43435b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(hdr->bt, hdr->bt_depth); 435e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev /* hdr->freed_bt_depth should be nonzero here */ 436e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n", 437e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 43835b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(hdr->freed_bt, hdr->freed_bt_depth); 439e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n", 440e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), hdr->size); 44135b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(bt, depth); 442e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 443e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev /* We take the memory out of the backlog and fall through so the 444e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * reallocation below succeeds. Since we didn't really free it, we 445e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev * can default to this behavior. 446e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev */ 447e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev del_from_backlog(hdr); 448c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes } else { 449e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n", 450e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev user(hdr), size); 45135b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(bt, depth); 452e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev // just get a whole new allocation and leak the old one 453e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return dlrealloc(0, size); 454e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev // return dlrealloc(user(hdr), size); // assuming it was allocated externally 455e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 456e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 457e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 4583d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris if (hdr->base != hdr) { 4593d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // An allocation from memalign, so create another allocation and 4603d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // copy the data out. 4613d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris void* newMem = dlmalloc(sizeof(hdr_t) + size + sizeof(ftr_t)); 4623d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris if (newMem) { 4633d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris memcpy(newMem, hdr, sizeof(hdr_t) + hdr->size); 4643d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris dlfree(hdr->base); 4653d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr = static_cast<hdr_t*>(newMem); 4663d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris } else { 4673d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris dlfree(hdr->base); 4683d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr = NULL; 4693d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris } 4703d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris } else { 4713d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr = static_cast<hdr_t*>(dlrealloc(hdr, sizeof(hdr_t) + size + sizeof(ftr_t))); 4723d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris } 473e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (hdr) { 4743d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr->base = hdr; 475e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH); 476e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev add(hdr, size); 477e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return user(hdr); 478e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 479e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 480e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return NULL; 481e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 482e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 4833d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisextern "C" void* chk_calloc(int nmemb, size_t size) { 484e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev// log_message("%s: %s\n", __FILE__, __FUNCTION__); 485e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev size_t total_size = nmemb * size; 486c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes hdr_t* hdr = static_cast<hdr_t*>(dlcalloc(1, sizeof(hdr_t) + total_size + sizeof(ftr_t))); 487e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev if (hdr) { 4883d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris hdr->base = hdr; 4891e980b6bc8315d00a07312b25486531247abd98cElliott Hughes hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH); 490e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev add(hdr, total_size); 491e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return user(hdr); 492e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 493e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev return NULL; 494e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 495e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 4963d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferrisextern "C" size_t chk_malloc_usable_size(const void* ptr) { 4973d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // dlmalloc_usable_size returns 0 for NULL and unknown blocks. 4983d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris if (ptr == NULL) 4993d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris return 0; 5003d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris 5013d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris const hdr_t* hdr = const_meta(ptr); 5023d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris 5033d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // The sentinel tail is written just after the request block bytes 5043d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris // so there is no extra room we can report here. 5053d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris return hdr->size; 5063d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris} 5073d594c258045783fc9e1956ce7a4d91e302f011eChristopher Ferris 5089c81892c2e8c684e0da12028e389bf6d9b5253b7Elliott Hughesstatic void ReportMemoryLeaks() { 5099c81892c2e8c684e0da12028e389bf6d9b5253b7Elliott Hughes // We only track leaks at level 10. 5109c81892c2e8c684e0da12028e389bf6d9b5253b7Elliott Hughes if (gMallocDebugLevel != 10) { 5119c81892c2e8c684e0da12028e389bf6d9b5253b7Elliott Hughes return; 5129c81892c2e8c684e0da12028e389bf6d9b5253b7Elliott Hughes } 5139c81892c2e8c684e0da12028e389bf6d9b5253b7Elliott Hughes 514239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes // Use /proc/self/exe link to obtain the program name for logging 515239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes // purposes. If it's not available, we set it to "<unknown>". 516239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes char exe[PATH_MAX]; 517239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes int count; 518239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes if ((count = readlink("/proc/self/exe", exe, sizeof(exe) - 1)) == -1) { 519239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes strlcpy(exe, "<unknown>", sizeof(exe)); 520239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes } else { 521239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes exe[count] = '\0'; 522239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes } 523e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 5241d12d574169cedd68185196e4957597d00fd4681Elliott Hughes if (gAllocatedBlockCount == 0) { 5251d12d574169cedd68185196e4957597d00fd4681Elliott Hughes log_message("+++ %s did not leak", exe); 5261d12d574169cedd68185196e4957597d00fd4681Elliott Hughes return; 5271d12d574169cedd68185196e4957597d00fd4681Elliott Hughes } 5281d12d574169cedd68185196e4957597d00fd4681Elliott Hughes 529239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes size_t index = 1; 530239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes const size_t total = gAllocatedBlockCount; 531239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes while (head != NULL) { 532239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes int safe; 533239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes hdr_t* block = head; 534239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes log_message("+++ %s leaked block of size %d at %p (leak %d of %d)", 535239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes exe, block->size, user(block), index++, total); 536239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes if (del_leak(block, &safe)) { 537239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes /* safe == 1, because the allocation is valid */ 53835b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes log_backtrace(block->bt, block->bt_depth); 539e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev } 540239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes } 541239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes 542239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes while (backlog_head != NULL) { 543239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes del_from_backlog(backlog_tail); 544239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes } 545e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 546e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 547c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" int malloc_debug_initialize() { 54835b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes backtrace_startup(); 5491e980b6bc8315d00a07312b25486531247abd98cElliott Hughes return 0; 550e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 551e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev 552c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void malloc_debug_finalize() { 5539c81892c2e8c684e0da12028e389bf6d9b5253b7Elliott Hughes ReportMemoryLeaks(); 55435b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes backtrace_shutdown(); 555e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev} 556