diff --git a/README.md b/README.md index 6c73163..8bdaba6 100644 --- a/README.md +++ b/README.md @@ -49,5 +49,8 @@ This is a incomplete and unordered roadmap of features I want to add and have ad \*: Implemented but untested. \*\*: Partially implemented. +# Tracing leaks +You can build numem with the `--debug=trace` flag to trace destruction of types via stdout. + # Note Some parts of the library will pretend GC'ed types are no-gc, as such you should be careful about mixing GCed code in. \ No newline at end of file diff --git a/source/numem/all.d b/source/numem/all.d index b2f576b..faa0183 100644 --- a/source/numem/all.d +++ b/source/numem/all.d @@ -9,4 +9,5 @@ public import numem.mem.string; public import numem.mem.vector; public import numem.mem.map; public import numem.mem.set; +public import numem.mem.exception; public import numem.io; diff --git a/source/numem/mem/exception.d b/source/numem/mem/exception.d index 248ffad..9282f43 100644 --- a/source/numem/mem/exception.d +++ b/source/numem/mem/exception.d @@ -5,6 +5,7 @@ module numem.mem.exception; import numem.mem.string; import numem.mem; import core.stdc.stdio; +import numem.mem.internal.trace; @nogc: @@ -19,9 +20,6 @@ private: public: ~this() { - // Debug build printing - debug printf("Exception freed! (msg=%s)\n", _msg.toCString()); - nogc_delete(_msg); // Free next-in-chain diff --git a/source/numem/mem/internal/trace.d b/source/numem/mem/internal/trace.d new file mode 100644 index 0000000..2b2776c --- /dev/null +++ b/source/numem/mem/internal/trace.d @@ -0,0 +1,37 @@ +/* + Copyright © 2023, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna Nielsen +*/ + +/** + Debug tracing module +*/ +module numem.mem.internal.trace; +import core.stdc.stdio; + +pragma(inline, true) +void dbg_alloc(T)(T item) if (is(T == class)) { + debug(trace) printf("Allocated "~T.stringof~" @ %p\n", cast(void*)item); +} + +pragma(inline, true) +void dbg_alloc(T)(T* item) if (is(T == struct)) { + debug(trace) printf("Allocated "~T.stringof~" @ %p\n", cast(void*)item); +} + +pragma(inline, true) +void dbg_alloc(T)(T* item) if (!is(T == struct) && !is(T == class)) { + debug(trace) printf("Allocated "~T.stringof~" @ %p\n", cast(void*)item); +} + +pragma(inline, true) +void dbg_dealloc(T)(ref T item) if (is(T == class)) { + debug(trace) printf("Freed "~T.stringof~" @ %p\n", cast(void*)item); +} + +pragma(inline, true) +void dbg_dealloc(T)(ref T item) if (!is(T == class)) { + debug(trace) printf("Freed "~T.stringof~"\n"); +} \ No newline at end of file diff --git a/source/numem/mem/package.d b/source/numem/mem/package.d index e6aba76..d2e6251 100644 --- a/source/numem/mem/package.d +++ b/source/numem/mem/package.d @@ -8,6 +8,7 @@ module numem.mem; import core.stdc.stdlib : free, exit, malloc; import std.traits; import numem.mem.utils; +import numem.mem.internal.trace; version(Have_tinyd_rt) { private __gshared @@ -97,6 +98,7 @@ T nogc_construct(T, Args...)(Args args) if (is(T == struct) || is(T == class) || Immediately exits the application if out of memory. */ T* nogc_new(T, Args...)(Args args) if (is(T == struct)) { + version(Have_tinyd_rt) { return (assumeNothrowNoGC(&__gc_new!(T, Args)))(args); } else { @@ -112,6 +114,9 @@ T* nogc_new(T, Args...)(Args args) if (is(T == struct)) { nogc_emplace!T(obj, args); } + // Tracing + debug(trace) dbg_alloc(obj); + return obj; } } @@ -121,6 +126,7 @@ T* nogc_new(T, Args...)(Args args) if (is(T == struct)) { Immediately exits the application if out of memory. */ T nogc_new(T, Args...)(Args args) if (is(T == class)) { + alias emplaceFunc = typeof(&emplace!T); version(Have_tinyd_rt) { @@ -140,8 +146,11 @@ T nogc_new(T, Args...)(Args args) if (is(T == class)) { // Allocate class T obj = nogc_emplace!T(rawMemory[destructorObjSize .. allocSize], args); - return obj; + // Tracing + debug(trace) dbg_alloc(obj); + + return obj; } else { immutable size_t allocSize = __traits(classInstanceSize, T); void* rawMemory = malloc(allocSize); @@ -163,6 +172,9 @@ T* nogc_new(T)(T value = T.init) if (isBasicType!T) { exit(-1); } + // Tracing + debug(trace) dbg_alloc(rawMemory); + *rawMemory = value; return rawMemory; } @@ -173,6 +185,9 @@ T* nogc_new(T)(T value = T.init) if (isBasicType!T) { For structs this will call the struct's destructor if it has any. */ void nogc_delete(T)(ref T obj_) { + + // Tracing + debug(trace) dbg_dealloc(obj_); version(minimal_rt) { static if (isPointer!T || is(T == class)) {