5 #pragma warning(disable: 4595)
9 #pragma clang diagnostic push
10 #pragma clang diagnostic ignored "-Winline-new-delete"
13#if defined(__GNUC__) && !defined(__clang__)
14 #pragma GCC diagnostic push
15 #pragma GCC diagnostic ignored "-Winline"
22#include <unordered_map>
27inline bool& is_tracking_disabled() {
28 thread_local bool disabled =
false;
32inline void print_stacktrace() {
33 bool was_disabled = is_tracking_disabled();
34 is_tracking_disabled() =
true;
36 std::cerr <<
"--- Stack trace ---\n";
37 std::cerr << std::stacktrace::current() <<
'\n';
39 is_tracking_disabled() = was_disabled;
42struct AllocationInfo {
44 std::stacktrace trace;
47struct AllocationTracker {
48 std::unordered_map<void*, AllocationInfo> active_ptrs;
50 bool is_destroyed =
false;
52 ~AllocationTracker() {
55 if (!active_ptrs.empty()) {
56 std::printf(
" WARNING: %zu allocation(s) were leaked!\n", active_ptrs.size());
58 for (
auto& [ptr, info] : active_ptrs) {
59 std::printf(
"\n[LEAK] Address: %p (%zu bytes)\n", ptr, info.size);
60 std::cerr <<
"Allocated by:\n" << info.trace <<
"\n";
68inline AllocationTracker& get_tracker() {
69 static AllocationTracker tracker;
73inline void*
operator new(std::size_t size) {
74 void* ptr = std::malloc(size);
76 throw std::bad_alloc();
79 if (!is_tracking_disabled()) {
80 is_tracking_disabled() =
true;
82 if (!get_tracker().is_destroyed) {
83 auto trace = std::stacktrace::current(1);
85 std::lock_guard<std::mutex> lock(get_tracker().mtx);
86 get_tracker().active_ptrs[ptr] = { size, std::move(trace) };
89 is_tracking_disabled() =
false;
95inline void track_delete(
void* ptr) {
98 if (!is_tracking_disabled()) {
99 is_tracking_disabled() =
true;
101 if (!get_tracker().is_destroyed) {
102 std::lock_guard<std::mutex> lock(get_tracker().mtx);
103 auto& ptrs = get_tracker().active_ptrs;
104 auto it = ptrs.find(ptr);
106 if (it != ptrs.end()) {
109 std::printf(
"\n[!!!] CRITICAL ERROR: Double free or untracked free at %p\n\n", ptr);
114 is_tracking_disabled() =
false;
120inline void operator delete(
void* ptr)
noexcept { track_delete(ptr); }
121inline void operator delete(
void* ptr, std::size_t)
noexcept { track_delete(ptr); }
123inline void*
operator new[](std::size_t size) {
return operator new(size); }
124inline void operator delete[](
void* ptr)
noexcept { track_delete(ptr); }
125inline void operator delete[](
void* ptr, std::size_t)
noexcept { track_delete(ptr); }
129#if defined(__GNUC__) && !defined(__clang__)
130 #pragma GCC diagnostic pop
133#if defined(__clang__)
134 #pragma clang diagnostic pop