#define _GNU_SOURCE #include #include #include #include #include /* glibc 验收探针,不进入运行库;插桩耗时与 RSS 不用于性能比较。 * 只跟踪这些入口实际返回的请求字节,忽略 loader 内部产生的未知指针。 * 固定表不调用分配器,表满直接使验收失败,不能悄悄漏记。 */ extern void *__libc_malloc(size_t size); extern void *__libc_calloc(size_t count, size_t size); extern void *__libc_realloc(void *pointer, size_t size); extern void __libc_free(void *pointer); extern void *__libc_memalign(size_t alignment, size_t size); #define CAPACITY 131072 #define DELETED ((uintptr_t)1) static struct { uintptr_t address; size_t size; } entries[CAPACITY]; static size_t allocations, releases, allocated_bytes, released_bytes, live_bytes, peak_bytes; static int recording = 1; static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static size_t slot(uintptr_t address, int insert) { size_t first_deleted = CAPACITY; size_t start = (address >> 4) % CAPACITY; for (size_t step = 0; step < CAPACITY; step++) { size_t index = (start + step) % CAPACITY; if (entries[index].address == address) return index; if (entries[index].address == DELETED && first_deleted == CAPACITY) first_deleted = index; if (!entries[index].address) return insert && first_deleted != CAPACITY ? first_deleted : index; } if (insert && first_deleted != CAPACITY) return first_deleted; abort(); } static void added(void *pointer, size_t size) { if (!recording || !pointer) return; uintptr_t address = (uintptr_t)pointer; size_t index = slot(address, 1); if (entries[index].address == address) abort(); entries[index].address = address; entries[index].size = size; allocations++; allocated_bytes += size; live_bytes += size; if (live_bytes > peak_bytes) peak_bytes = live_bytes; } static void removed(uintptr_t address) { if (!recording || !address) return; size_t index = slot(address, 0); if (entries[index].address != address) return; releases++; released_bytes += entries[index].size; live_bytes -= entries[index].size; entries[index].address = DELETED; } void *malloc(size_t size) { pthread_mutex_lock(&lock); void *pointer = __libc_malloc(size); added(pointer, size); pthread_mutex_unlock(&lock); return pointer; } void *calloc(size_t count, size_t size) { pthread_mutex_lock(&lock); void *pointer = __libc_calloc(count, size); if (pointer) added(pointer, count * size); pthread_mutex_unlock(&lock); return pointer; } void *realloc(void *pointer, size_t size) { pthread_mutex_lock(&lock); uintptr_t address = (uintptr_t)pointer; void *result = __libc_realloc(pointer, size); /* 失败时旧块仍存活;glibc 的零大小 realloc 则释放旧块。 */ if (result || size == 0) { removed(address); added(result, size); } pthread_mutex_unlock(&lock); return result; } int posix_memalign(void **result, size_t alignment, size_t size) { if (alignment < sizeof(void *) || (alignment & (alignment - 1))) return EINVAL; int previous_errno = errno; pthread_mutex_lock(&lock); void *pointer = __libc_memalign(alignment, size); if (pointer) { *result = pointer; added(pointer, size); } pthread_mutex_unlock(&lock); errno = previous_errno; return pointer ? 0 : ENOMEM; } void free(void *pointer) { pthread_mutex_lock(&lock); removed((uintptr_t)pointer); __libc_free(pointer); pthread_mutex_unlock(&lock); } __attribute__((destructor)) static void report(void) { pthread_mutex_lock(&lock); recording = 0; pthread_mutex_unlock(&lock); fprintf(stderr, "heap_stats,%zu,%zu,%zu,%zu,%zu,%zu\n", allocations, releases, allocated_bytes, released_bytes, live_bytes, peak_bytes); }