Skip to content

Instantly share code, notes, and snippets.

@dortamiguel
Created December 20, 2024 02:57
Show Gist options
  • Save dortamiguel/b3d681a1d2ef37f2c975828d13f44476 to your computer and use it in GitHub Desktop.
Save dortamiguel/b3d681a1d2ef37f2c975828d13f44476 to your computer and use it in GitHub Desktop.
function memory leak
#include <pthread.h>
template <typename... Args> struct function {
void (*callable)(void *, Args...) = nullptr;
static constexpr u32 MAX_CONTEXT_SIZE = 32;
char *context = nullptr;
function() : context(new char[MAX_CONTEXT_SIZE]) {}
template <typename Type> function(Type _function) : function() {
*this = std::move(_function);
}
template <typename Type> function &operator=(Type _function) {
struct Context {
Type function;
Context(Type function) : function(std::move(function)) {}
void invoke(Args... args) {
function(args...);
}
};
static_assert(sizeof(Context) <= MAX_CONTEXT_SIZE, "context size is too small");
new (context) Context(std::move(_function));
callable = [](void *_context, Args... args) {
static_cast<Context *>(_context)->invoke(args...);
};
return *this;
}
~function() = default;
void operator()(Args... args) {
if (callable) {
callable((void *)context, args...);
}
}
};
struct thread {
void *handle = nullptr;
function<> task;
thread(function<> &&task) : task(std::move(task)) {
#if _WIN64
handle = CreateThread(
nullptr, 0, (LPTHREAD_START_ROUTINE)task.callable, (void *)task.context, 0, nullptr
);
#else
handle = malloc(sizeof(pthread_t));
pthread_create(
(pthread_t *)handle, nullptr, (void *(*)(void *))task.callable, (void *)task.context
);
#endif
}
~thread() {
detach();
}
void join() {
if (!handle) return;
#if _WIN64
WaitForSingleObject(handle, INFINITE);
#else
pthread_join(*(pthread_t *)handle, NULL);
#endif
detach();
}
void detach() {
if (!handle) return;
#if _WIN64
CloseHandle(handle);
#else
pthread_detach(*(pthread_t *)handle);
free(handle);
#endif
handle = nullptr;
}
};
// Usage examples
void main() {
thread audio_loop([]() {
while (!input.exit) {
music.update();
}
});
// game loop goes here
audio_loop.join();
}
void Level::async_save() {
thread([&]() { save(); }).detach();
}
// If I add a destructor to function
~function() {
if (context) {
delete[] context;
}
}
// I get this error
/*
thread main_font_load([&]() { main_font.load("source_code_pro_regular.ttf"); });
thread emoji_font_load([&]() { emoji_font.load("noto_emoji_regular.ttf"); });
thread japanese_font_load([&]() { japanese_font.load("noto_sans_jp_regular.ttf"); });
main_font_load.join();
emoji_font_load.join();
japanese_font_load.join();
=================================================================
==80797==ERROR: AddressSanitizer: attempting double-free on 0x00013863ad20 in thread T5:
#0 0x125175c88 in wrap__ZdaPv+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x61c88)
#1 0x1046e976c in thread::~thread() base.cpp:292
#2 0x1047de7a0 in Fonts::load() font.cpp:127
#3 0x19d37ef90 in _pthread_start+0x84 (libsystem_pthread.dylib:arm64e+0x6f90)
#4 0x19d379d30 in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d30)
0x00013863ad20 is located 0 bytes inside of 32-byte region [0x00013863ad20,0x00013863ad40)
freed by thread T5 here:
#0 0x125175c88 in wrap__ZdaPv+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x61c88)
#1 0x1047de778 in Fonts::load() font.cpp:123
#2 0x19d37ef90 in _pthread_start+0x84 (libsystem_pthread.dylib:arm64e+0x6f90)
#3 0x19d379d30 in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d30)
previously allocated by thread T5 here:
#0 0x125175874 in wrap__Znam+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x61874)
#1 0x1047de700 in Fonts::load() font.cpp:123
#2 0x19d37ef90 in _pthread_start+0x84 (libsystem_pthread.dylib:arm64e+0x6f90)
#3 0x19d379d30 in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d30)
Thread T5 created by T0 here:
#0 0x12515fd6c in wrap_pthread_create+0x54 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x4bd6c)
#1 0x1046e950c in thread::thread(function<>&&) base.cpp:279
#2 0x10499c7a4 in main main.cpp:72
#3 0x19cff60dc (<unknown module>)
SUMMARY: AddressSanitizer: double-free (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x61c88) in wrap__ZdaPv+0x74
==80797==ABORTING
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment