Skip to content

Instantly share code, notes, and snippets.

@jacky860226
Created March 7, 2026 07:12
Show Gist options
  • Select an option

  • Save jacky860226/2cb0e1fdbc5b74cd93f32d138e1145fe to your computer and use it in GitHub Desktop.

Select an option

Save jacky860226/2cb0e1fdbc5b74cd93f32d138e1145fe to your computer and use it in GitHub Desktop.
Memory Hooking
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <dlfcn.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <new>
#include <cstdarg>
#include <mutex>
#include <sys/mman.h>
#include <cerrno>
#include <sys/syscall.h>
#include <chrono>
#include <atomic>
#include <malloc.h>
#include <unordered_set>
#include <algorithm>
#include <vector>
#include <ctime>
// 1. 定義函式指標型別
// classic functions
using CallocFunc = decltype(calloc);
using FreeFunc = decltype(free);
using MallocFunc = decltype(malloc);
using ReallocFunc = decltype(realloc);
// pagesize functions
using VallocFunc = decltype(valloc);
using MemalignFunc = decltype(memalign);
using Posix_memalignFunc = decltype(posix_memalign);
using Aligned_allocFunc = decltype(aligned_alloc);
// mmap/munmap
using MmapFunc = decltype(mmap);
using Mmap64Func = decltype(mmap64);
using MunmapFunc = decltype(munmap);
using MallocUsableSizeFunc = decltype(malloc_usable_size);
// 2. 全域變數
static CallocFunc *callocFunc = nullptr;
static FreeFunc *freeFunc = nullptr;
static MallocFunc *mallocFunc = nullptr;
static ReallocFunc *reallocFunc = nullptr;
static VallocFunc *vallocFunc = nullptr;
static MemalignFunc *memalignFunc = nullptr;
static Posix_memalignFunc *posix_memalignFunc = nullptr;
static Aligned_allocFunc* aligned_allocFunc = nullptr;
static MmapFunc *mmapFunc = nullptr;
static Mmap64Func *mmap64Func = nullptr;
static MunmapFunc *munmapFunc = nullptr;
static MallocUsableSizeFunc *mallocUsableSizeFunc = nullptr;
static std::atomic<bool> initialized{false};
static std::atomic<bool> initializing{false};
// Static Buffer 設定 (128MB)
static constexpr auto KB = 1024UL;
static constexpr auto MB = 1024UL * 1024UL;
static constexpr size_t StaticMemorySize = 128 * MB;
static char staticMemory[StaticMemorySize];
static char *staticPtr = staticMemory;
static size_t totalStaticSize = 0;
static size_t lastStaticAlloc = 0;
static std::recursive_mutex mtStaticMem;
static std::timed_mutex mtLog;
// 3. 輔助函式
/**
* @brief RAII 輔助類別,用於在解構時恢復變數的原始值。
*
* 這在防止遞迴呼叫或暫時修改全域狀態時非常有用。
*/
template <typename T>
class Keep {
T &ref_;
T oldvalue_;
public:
explicit Keep (T &var) : ref_(var), oldvalue_(var) { }
Keep (T &var, T value) : ref_(var), oldvalue_(var) {
var = value;
}
~Keep () {
ref_ = oldvalue_;
}
Keep(const Keep&) = delete;
Keep& operator=(const Keep&) = delete;
};
/**
* @brief 記憶體配置紀錄結構。
*
* 儲存單次記憶體配置的指標位址、大小以及配置時間。
*/
struct MemoryRec {
void *ptr_; ///< 配置的記憶體起始位址
size_t size_; ///< 配置的大小 (bytes)
std::chrono::time_point<std::chrono::system_clock> time_; ///< 配置發生的時間點
MemoryRec(void *ptr, size_t size) : ptr_(ptr), size_(size), time_(std::chrono::system_clock::now()) {}
MemoryRec(void *ptr) : ptr_(ptr), size_(0) {}
};
struct MemoryRecOp {
size_t operator()(const MemoryRec* rec) const {
return std::hash<void*>()(rec->ptr_);
}
bool operator()(const MemoryRec* a, const MemoryRec* b) const {
return a->ptr_ == b->ptr_;
}
};
/**
* @brief 管理所有記憶體配置紀錄的類別。
*
* 使用雜湊集合 (unordered_set) 儲存紀錄,並提供執行緒安全的操作介面。
*/
class MemoryRecords {
std::unordered_set<MemoryRec*, MemoryRecOp, MemoryRecOp> records_;
// 使用 std::mutex 即可。
// 雖然 malloc/free 可能在多執行緒環境下頻繁呼叫,但我們在 Dump 時採用 Snapshot 策略,
// 複製完資料即釋放鎖,不會在持有鎖的期間呼叫可能導致遞迴鎖定的外部函式。
std::mutex lock_;
public:
/**
* @brief 新增一筆記憶體配置紀錄。
*
* @param ptr 配置的記憶體指標。
* @param size 配置的大小。
*/
void Add(void* ptr, size_t size) {
std::lock_guard<std::mutex> guard(lock_);
records_.insert(new MemoryRec(ptr, size));
}
/**
* @brief 移除一筆記憶體配置紀錄。
*
* 當記憶體被釋放 (free) 時呼叫此函式。
*
* @param ptr 要釋放的記憶體指標。
*/
void Remove(void* ptr) {
std::lock_guard<std::mutex> guard(lock_);
MemoryRec searchKey(ptr);
auto it = records_.find(&searchKey);
if (it != records_.end()) {
delete *it;
records_.erase(it);
}
}
/**
* @brief 查詢指定記憶體位址的配置紀錄。
*
* @param ptr 記憶體指標。
* @return const MemoryRec* 記憶體紀錄指標 (若找不到則回傳 nullptr)。
*/
const MemoryRec* Find(void* ptr) {
std::lock_guard<std::mutex> guard(lock_);
MemoryRec searchKey(ptr);
auto it = records_.find(&searchKey);
if (it != records_.end()) {
return *it;
}
return nullptr;
}
/**
* @brief 將目前的記憶體紀錄輸出到指定的檔案串流。
*
* 實作細節與設計考量:
* 1. **Snapshot (快照) 策略**:
* 先在 Critical Section (持有 lock_ 期間) 將所有紀錄複製到 local vector。
* 這讓我們能盡快釋放鎖,避免在進行緩慢的 I/O 操作 (fprintf) 時阻塞其他執行緒的 malloc/free。
* 若在持有鎖的情況下做 I/O,會嚴重影響程式效能,甚至增加 Deadlock 風險。
*
* 2. **時間排序**:
* 依據 time_ 欄位對快照進行排序,還原記憶體配置的發生順序,方便閱讀。
*
* 3. **執行緒安全的時間格式化**:
* 使用 ctime_r 取代 ctime。ctime 使用內部的 Static Buffer,在多執行緒下不安全 (Race Condition)。
*
* @param stream 輸出的目標檔案串流 (例如 stdout 或 stderr)。
*/
void Dump(FILE* stream) {
std::vector<MemoryRec> tempRecords;
{
std::lock_guard<std::mutex> guard(lock_);
tempRecords.reserve(records_.size());
for (auto* rec : records_) {
tempRecords.push_back(*rec);
}
}
std::sort(tempRecords.begin(), tempRecords.end(), [](const MemoryRec& a, const MemoryRec& b) {
return a.time_ < b.time_;
});
fprintf(stream, "=== Memory Records ===\n");
size_t total = 0;
for (const auto& rec : tempRecords) {
auto timet = std::chrono::system_clock::to_time_t(rec.time_);
char timeStr[26];
ctime_r(&timet, timeStr);
timeStr[24] = '\0'; // Remove newline
fprintf(stream, "[%s] Ptr: %p, Size: %zu\n", timeStr, rec.ptr_, rec.size_);
total += rec.size_;
}
fprintf(stream, "Total allocated: %zu bytes in %zu blocks\n", total, tempRecords.size());
fprintf(stream, "======================\n");
}
};
/**
* @brief 全域記憶體紀錄物件指標。
*
* 使用指標而非靜態物件實體,是為了手動控制其生命週期 (Life-cycle)。
* 避免在程式結束 (exit) 階段,靜態物件已被解構後,仍有其他解構子呼叫 free() 導致 Crash。
*/
static MemoryRecords* g_records = nullptr;
/**
* @brief 執行緒區域 (Thread-local) 的遞迴防止旗標。
*
* 這是 Malloc Hook 最核心的保護機制。
* 當我們在 malloc/free Hook 內部執行邏輯 (如 g_records->Add) 時,
* 這些邏輯本身 (例如 STL 容器操作) 也會呼叫 malloc/free。
* 若沒有此旗標,會導致無限遞迴 (Infinite Recursion) 直到 Stack Overflow。
*
* 流程:
* 1. 進入 malloc Hook
* 2. 檢查 insideBase,若為 true 則直接呼叫原始 malloc (不紀錄)
* 3. 設定 insideBase = true
* 4. 執行紀錄邏輯 (可能觸發 malloc -> 步驟 1 -> 步驟 2 -> 返回)
* 5. 恢復 insideBase = false
*/
static thread_local bool insideBase = false;
// Round up to alignment
template <typename T>
inline T RoundUp(T n, T roundTo) {
return roundTo ? ((n + roundTo - 1) / roundTo) * roundTo : 0;
}
inline void *AlignPointer(void *ptr, size_t align) {
return (void *) (((size_t) ptr + align - 1) / align * align);
}
bool IsStaticMemory(void *ptr) {
return ptr >= staticMemory && ptr < staticMemory + StaticMemorySize;
}
void *StaticAlloc(size_t size, size_t alignment) {
std::lock_guard<std::recursive_mutex> lock(mtStaticMem);
totalStaticSize += size;
staticPtr = (char *) AlignPointer(staticPtr, alignment);
if (staticPtr + size > staticMemory + StaticMemorySize) {
const char* msg = "*** no more static memory ***\n";
write(STDERR_FILENO, msg, strlen(msg));
abort();
}
void *ptr = staticPtr;
staticPtr += size;
lastStaticAlloc = size;
return ptr;
}
void StaticFree(void *ptr) {
std::lock_guard<std::recursive_mutex> lock(mtStaticMem);
if (staticPtr - lastStaticAlloc == ptr) {
staticPtr = (char *) ptr;
}
}
void *StaticRealloc(void *ptr, size_t size) {
std::lock_guard<std::recursive_mutex> lock(mtStaticMem);
if (ptr == staticPtr - lastStaticAlloc) {
if ((char*)ptr + size > staticMemory + StaticMemorySize) {
const char* msg = "*** no more static memory (realloc) ***\n";
write(STDERR_FILENO, msg, strlen(msg));
abort();
}
long delta = long(size - lastStaticAlloc);
totalStaticSize += delta;
staticPtr += delta;
lastStaticAlloc = size;
return ptr;
}
void *newPtr = StaticAlloc(size, 8);
size_t offset = (char*)ptr - staticMemory;
size_t oldSize = (size < offset) ? size : offset;
memmove(newPtr, ptr, oldSize);
return newPtr;
}
void InitializePointers() {
if (initialized) return;
initializing = true;
// 使用 RTLD_NEXT 載入 libc 符號
callocFunc = (CallocFunc *)dlsym(RTLD_NEXT, "calloc");
freeFunc = (FreeFunc *)dlsym(RTLD_NEXT, "free");
mallocFunc = (MallocFunc *)dlsym(RTLD_NEXT, "malloc");
reallocFunc = (ReallocFunc *)dlsym(RTLD_NEXT, "realloc");
vallocFunc = (VallocFunc *)dlsym(RTLD_NEXT, "valloc");
memalignFunc = (MemalignFunc *)dlsym(RTLD_NEXT, "memalign");
posix_memalignFunc = (Posix_memalignFunc *)dlsym(RTLD_NEXT, "posix_memalign");
aligned_allocFunc = (Aligned_allocFunc *)dlsym(RTLD_NEXT, "aligned_alloc");
mmapFunc = (MmapFunc *)dlsym(RTLD_NEXT, "mmap");
mmap64Func = (Mmap64Func *)dlsym(RTLD_NEXT, "mmap64");
munmapFunc = (MunmapFunc *)dlsym(RTLD_NEXT, "munmap");
mallocUsableSizeFunc = (MallocUsableSizeFunc *)dlsym(RTLD_NEXT, "malloc_usable_size");
if (!g_records) {
bool old = insideBase;
insideBase = true;
g_records = new MemoryRecords();
insideBase = old;
}
initialized = true;
initializing = false;
}
void Initialize() {
if (initializing) return;
if (!initialized) InitializePointers();
}
/**
* @brief 執行緒安全的日誌輸出函式。
*
* 關鍵實作細節:
* 1. **防止無限遞迴 (Infinite Recursion)**:
* printf/snprintf 內部實作可能會呼叫 malloc。
* 若不檢查 insideLog 旗標,流程會變成:Log -> snprintf -> malloc -> Log -> snprintf ... 導致 Stack Overflow。
* 這是撰寫 Malloc Hook 時最容易踩到的坑。
*
* 2. **保存 errno**:
* 使用 Keep<int> 保存並恢復 errno,避免 Log 內部的系統呼叫改變了 errno,
* 導致原本程式邏輯判斷錯誤 (例如原本 malloc 失敗設了 ENOMEM,卻被 Log 蓋掉)。
*
* @param fmt 格式化字串。
* @param ... 可變參數。
*/
void Log(const char* fmt, ...) {
// 防止 Log 內部 (如 vsnprintf) 再次呼叫 malloc 導致無限遞迴
static thread_local bool insideLog = false;
if (insideLog) return;
Keep<bool> k(insideLog, true);
Keep<int> kErrno(errno); // 保存 errno,避免 Log 影響程式邏輯
char buf[1024];
// 加上 Thread ID 方便除錯
int len = snprintf(buf, sizeof(buf), "[TID:%ld] ", syscall(SYS_gettid));
va_list args;
va_start(args, fmt);
len += vsnprintf(buf + len, sizeof(buf) - len, fmt, args);
va_end(args);
if (len >= (int)sizeof(buf)) {
len = sizeof(buf);
buf[sizeof(buf) - 1] = '\0';
}
if (!mtLog.try_lock_for(std::chrono::milliseconds(100))) {
const char* msg = "Cannot lock mtLog\n";
write(STDERR_FILENO, msg, strlen(msg));
return;
}
std::unique_lock<std::timed_mutex> lock(mtLog, std::adopt_lock);
write(STDERR_FILENO, buf, len);
}
extern "C" {
/**
* @brief C 語言介面:輸出記憶體紀錄。
*
* 使用 extern "C" 宣告以關閉 C++ Name Mangling (名稱修飾)。
* 這有兩個重要目的:
* 1. **跨語言相容**:讓純 C 語言撰寫的程式也能連結並呼叫此函式。
* 2. **動態載入支援**:若使用 dlsym (Dynamic Loading) 取得函式位址,
* 必須使用未修飾的名稱 "dump_memory_records" 才能找到符號。
*
* @param stream 輸出的目標檔案串流。
*/
void dump_memory_records(FILE* stream) {
if (g_records) {
Keep<bool> k(insideBase, true);
g_records->Dump(stream);
}
}
void *calloc(size_t nmemb, size_t size) {
if (initializing) {
if (callocFunc == nullptr) {
auto ptr = StaticAlloc(nmemb * size, 8);
if (ptr) memset(ptr, 0, nmemb * size);
return ptr;
}
return (*callocFunc)(nmemb, size);
}
Initialize();
if (insideBase) return (*callocFunc)(nmemb, size);
void* ptr = (*callocFunc)(nmemb, size);
if (ptr && g_records) {
Keep<bool> k(insideBase, true);
g_records->Add(ptr, nmemb * size);
}
Log("[calloc] nmemb: %zu, size: %zu\n", nmemb, size);
return ptr;
}
void free(void *ptr) {
if (ptr == nullptr) return;
if (IsStaticMemory(ptr)) {
StaticFree(ptr);
return;
}
if (initializing && freeFunc == nullptr) return;
Initialize();
if (insideBase) {
(*freeFunc)(ptr);
return;
}
if (g_records) {
Keep<bool> k(insideBase, true);
g_records->Remove(ptr);
}
Log("[free] ptr: %p\n", ptr);
(*freeFunc)(ptr);
}
void cfree(void *ptr) {
free(ptr);
}
void *malloc(size_t size) {
if (initializing) return StaticAlloc(size, 8);
Initialize();
if (insideBase) return (*mallocFunc)(size);
void* ptr = (*mallocFunc)(size);
if (ptr && g_records) {
Keep<bool> k(insideBase, true);
g_records->Add(ptr, size);
}
Log("[malloc] size: %zu, ptr: %p\n", size, ptr);
return ptr;
}
void *realloc(void *ptr, size_t size) {
if (IsStaticMemory(ptr)) return StaticRealloc(ptr, size);
if (initializing && reallocFunc == nullptr) return StaticAlloc(size, 8);
Initialize();
if (insideBase) return (*reallocFunc)(ptr, size);
void* new_ptr = (*reallocFunc)(ptr, size);
if (new_ptr && g_records) {
Keep<bool> k(insideBase, true);
if (ptr) g_records->Remove(ptr);
g_records->Add(new_ptr, size);
}
Log("[realloc] old: %p, size: %zu, new: %p\n", ptr, size, new_ptr);
return new_ptr;
}
void *valloc(size_t size) {
static auto pagesize = (size_t)sysconf(_SC_PAGESIZE);
if (initializing) return StaticAlloc(size, pagesize);
Initialize();
if (insideBase) return (*vallocFunc)(size);
void* ptr = (*vallocFunc)(size);
if (ptr && g_records) {
Keep<bool> k(insideBase, true);
g_records->Add(ptr, size);
}
Log("[valloc] size: %zu\n", size);
return ptr;
}
void *pvalloc(size_t size) {
static auto pagesize = (size_t)sysconf(_SC_PAGESIZE);
Log("[pvalloc] size: %zu\n", size);
return memalign(pagesize, RoundUp(size, pagesize));
}
void *memalign(size_t alignment, size_t size) {
if (initializing) return StaticAlloc(size, alignment);
Initialize();
if (insideBase) return (*memalignFunc)(alignment, size);
void* ptr = (*memalignFunc)(alignment, size);
if (ptr && g_records) {
Keep<bool> k(insideBase, true);
g_records->Add(ptr, size);
}
Log("[memalign] align: %zu, size: %zu\n", alignment, size);
return ptr;
}
int posix_memalign(void **memptr, size_t alignment, size_t size) {
if (initializing) {
*memptr = StaticAlloc(size, alignment);
return 0;
}
Initialize();
if (insideBase) return (*posix_memalignFunc)(memptr, alignment, size);
int ret = (*posix_memalignFunc)(memptr, alignment, size);
if (ret == 0 && *memptr && g_records) {
Keep<bool> k(insideBase, true);
g_records->Add(*memptr, size);
}
Log("[posix_memalign] align: %zu, size: %zu\n", alignment, size);
return ret;
}
void *aligned_alloc(size_t alignment, size_t size) {
if (initializing) return StaticAlloc(size, alignment);
Initialize();
if (insideBase) return (*aligned_allocFunc)(alignment, size);
void* ptr = (*aligned_allocFunc)(alignment, size);
if (ptr && g_records) {
Keep<bool> k(insideBase, true);
g_records->Add(ptr, size);
}
Log("[aligned_alloc] align: %zu, size: %zu\n", alignment, size);
return ptr;
}
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
if (initializing) {
if (mmapFunc == nullptr) return StaticAlloc(length, 8);
return (*mmapFunc)(addr, length, prot, flags, fd, offset);
}
Initialize();
if (insideBase) return (*mmapFunc)(addr, length, prot, flags, fd, offset);
void* ptr = (*mmapFunc)(addr, length, prot, flags, fd, offset);
Log("[mmap] len: %zu, ptr: %p\n", length, ptr);
return ptr;
}
void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off64_t offset) {
if (initializing) {
if (mmap64Func == nullptr) return StaticAlloc(length, 8);
return (*mmap64Func)(addr, length, prot, flags, fd, offset);
}
Initialize();
if (insideBase) return (*mmap64Func)(addr, length, prot, flags, fd, offset);
void* ptr = (*mmap64Func)(addr, length, prot, flags, fd, offset);
Log("[mmap64] len: %zu, ptr: %p\n", length, ptr);
return ptr;
}
int munmap(void *addr, size_t length) {
if (initializing) return 0;
Initialize();
if (insideBase) return (*munmapFunc)(addr, length);
Log("[munmap] addr: %p, len: %zu\n", addr, length);
return (*munmapFunc)(addr, length);
}
size_t malloc_usable_size(void *ptr) {
// 絕對不能將 Static Memory 的指標傳給 glibc 的 malloc_usable_size,否則會 Crash
if (IsStaticMemory(ptr)) return 0;
if (initializing) return 0;
Initialize();
if (insideBase) return (*mallocUsableSizeFunc)(ptr);
if (g_records) {
Keep<bool> k(insideBase, true);
const MemoryRec* rec = g_records->Find(ptr);
if (rec) return rec->size_;
}
return 0;
}
} // extern "C"
// C++ Operators
void *operator new(size_t size) {
if (initializing) return StaticAlloc(size, 8);
Initialize();
if (insideBase) {
void* ptr = (*mallocFunc)(size);
if (!ptr) throw std::bad_alloc();
return ptr;
}
void* ptr = (*mallocFunc)(size);
if (ptr && g_records) {
Keep<bool> k(insideBase, true);
g_records->Add(ptr, size);
}
Log("[new] size: %zu, ptr: %p\n", size, ptr);
if (!ptr) throw std::bad_alloc();
return ptr;
}
void *operator new[](size_t size) {
if (initializing) return StaticAlloc(size, 8);
Initialize();
if (insideBase) {
void* ptr = (*mallocFunc)(size);
if (!ptr) throw std::bad_alloc();
return ptr;
}
void* ptr = (*mallocFunc)(size);
if (ptr && g_records) {
Keep<bool> k(insideBase, true);
g_records->Add(ptr, size);
}
Log("[new[]] size: %zu, ptr: %p\n", size, ptr);
if (!ptr) throw std::bad_alloc();
return ptr;
}
void operator delete(void *ptr) noexcept {
if (ptr == nullptr) return;
if (IsStaticMemory(ptr)) { StaticFree(ptr); return; }
if (initializing) return;
Initialize();
if (insideBase) {
(*freeFunc)(ptr);
return;
}
if (g_records) {
Keep<bool> k(insideBase, true);
g_records->Remove(ptr);
}
Log("[delete] ptr: %p\n", ptr);
(*freeFunc)(ptr);
}
void operator delete[](void *ptr) noexcept {
if (ptr == nullptr) return;
if (IsStaticMemory(ptr)) { StaticFree(ptr); return; }
if (initializing) return;
Initialize();
if (insideBase) {
(*freeFunc)(ptr);
return;
}
if (g_records) {
Keep<bool> k(insideBase, true);
g_records->Remove(ptr);
}
Log("[delete[]] ptr: %p\n", ptr);
(*freeFunc)(ptr);
}
// C++98 Nothrow New/Delete
void *operator new(size_t size, const std::nothrow_t &) noexcept {
if (initializing) return StaticAlloc(size, 8);
Initialize();
if (insideBase) return (*mallocFunc)(size);
void* ptr = (*mallocFunc)(size);
if (ptr && g_records) {
Keep<bool> k(insideBase, true);
g_records->Add(ptr, size);
}
Log("[new nothrow] size: %zu, ptr: %p\n", size, ptr);
return ptr;
}
void *operator new[](size_t size, const std::nothrow_t &) noexcept {
if (initializing) return StaticAlloc(size, 8);
Initialize();
if (insideBase) return (*mallocFunc)(size);
void* ptr = (*mallocFunc)(size);
if (ptr && g_records) {
Keep<bool> k(insideBase, true);
g_records->Add(ptr, size);
}
Log("[new[] nothrow] size: %zu, ptr: %p\n", size, ptr);
return ptr;
}
void operator delete(void *ptr, const std::nothrow_t &) noexcept {
free(ptr);
}
void operator delete[](void *ptr, const std::nothrow_t &) noexcept {
free(ptr);
}
// C++17 Aligned New/Delete
#if __cplusplus >= 201703L
void *operator new(size_t size, std::align_val_t al) {
return memalign(size_t(al), size);
}
void *operator new[](size_t size, std::align_val_t al) {
return memalign(size_t(al), size);
}
void *operator new(size_t size, std::align_val_t al, const std::nothrow_t &) noexcept {
return memalign(size_t(al), size);
}
void *operator new[](size_t size, std::align_val_t al, const std::nothrow_t &) noexcept {
return memalign(size_t(al), size);
}
void operator delete(void *ptr, std::align_val_t) noexcept {
free(ptr);
}
void operator delete[](void *ptr, std::align_val_t) noexcept {
free(ptr);
}
#endif
#define TEST
#ifdef TEST
#include <dirent.h>
#include <fcntl.h>
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#pragma GCC diagnostic ignored "-Wmismatched-new-delete"
extern "C" void dump_memory_records(FILE* stream);
int main ()
{
// Disable buffering for stdout to avoid the 4KB buffer allocation by the first printf
setvbuf(stdout, NULL, _IONBF, 0);
char *pc1 = new char;
printf("malloc_usable_size(pc1): %zu\n", malloc_usable_size(pc1));
//char *pc2 = new char;
char *pca1 = new char [11];
printf("malloc_usable_size(pca1): %zu\n", malloc_usable_size(pca1));
char *pca2 = new char [12];
printf("malloc_usable_size(pca2): %zu\n", malloc_usable_size(pca2));
double *pd = new double;
printf("malloc_usable_size(pd): %zu\n", malloc_usable_size(pd));
double *pda = new double[2];
printf("malloc_usable_size(pda): %zu\n", malloc_usable_size(pda));
memset (pca1, 1, 12);
delete pc1;
//delete [] pc1;
delete [] pca1;
delete pca2;
delete pd;
delete [] pda;
char *p = 0;
char s[101] = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
size_t sz = 0;
for (int i = 0 ; i < 200; i += 33) {
sz += 101;
p = (char*)realloc(p, sz);
printf("malloc_usable_size(p): %zu\n", malloc_usable_size(p));
strcpy(p+sz-101, s);
}
DIR *d = opendir(".");
closedir(d);
int f = open(".", O_RDONLY);
d = fdopendir(f);
(void)f;
dump_memory_records(stdout);
exit(0);
}
#endif // TEST
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment