Skip to content

Commit feb65a9

Browse files
authored
Merge pull request GaijinEntertainment#2676 from GaijinEntertainment/bbatkin/lexer-tracker-leak-fix
alloc-tracker: fix phantom lexer_track_map leaks; re-enable parallel-lint test
2 parents 13704ad + 3579ca6 commit feb65a9

4 files changed

Lines changed: 34 additions & 0 deletions

File tree

include/daScript/misc/platform.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,16 @@ namespace das {
386386
DAS_API void track_free_hook(void *p) noexcept;
387387
DAS_API void arm_alloc_tracking() noexcept;
388388
DAS_API size_t dump_alloc_leaks(FILE *out);
389+
// RAII: sets the tracker's tl_inside so allocations/frees inside the scope
390+
// are not recorded in the LeakMap. Use for internal bookkeeping containers
391+
// (e.g. lexer_track_map) whose operator delete during erase would otherwise
392+
// recurse into track_free_hook, bail on the already-true tl_inside, and
393+
// leave phantom LeakMap entries.
394+
struct DAS_API AllocTrackerInternalGuard {
395+
bool prev;
396+
AllocTrackerInternalGuard() noexcept;
397+
~AllocTrackerInternalGuard() noexcept;
398+
};
389399
// Landmark RAII: ctor walks the stack once and stores the chain; alloc-site
390400
// captures that match the landmark's RSP short-circuit with a memcpy. Place
391401
// one on the stack high in the call tree (e.g. top of compile_and_run) to
@@ -409,6 +419,10 @@ namespace das {
409419
inline void track_free_hook(void *) noexcept {}
410420
inline void arm_alloc_tracking() noexcept {}
411421
inline size_t dump_alloc_leaks(FILE *) { return 0; }
422+
struct AllocTrackerInternalGuard {
423+
AllocTrackerInternalGuard() noexcept {}
424+
~AllocTrackerInternalGuard() noexcept {}
425+
};
412426
struct AllocTrackingLandmark {
413427
AllocTrackingLandmark() noexcept {}
414428
~AllocTrackingLandmark() noexcept {}

src/misc/alloc_tracker.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,14 @@ void arm_alloc_tracking() noexcept {
217217
g_armed.store(true, std::memory_order_release);
218218
}
219219

220+
AllocTrackerInternalGuard::AllocTrackerInternalGuard() noexcept : prev(tl_inside) {
221+
tl_inside = true;
222+
}
223+
224+
AllocTrackerInternalGuard::~AllocTrackerInternalGuard() noexcept {
225+
tl_inside = prev;
226+
}
227+
220228
// ------------------------- Symbolization -------------------------
221229

222230
#if defined(_MSC_VER)

src/misc/lexer_alloc_track.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,24 @@ namespace das {
4040
void lexer_track_alloc(std::string *p, const char *tokenText) noexcept {
4141
if (!p || tl_inside) return;
4242
ReentryGuard g;
43+
// Internal: suppress LeakMap tracking for our map's own node allocations.
44+
// Otherwise the node alloc gets recorded in LeakMap; later, the matching
45+
// operator delete during m.erase runs while alloc_tracker's tl_inside is
46+
// already true (lexer_track_free is invoked from track_free_hook's
47+
// ReentryGuard scope), so the nested track_free_hook bails before
48+
// removing the entry, leaving a phantom leak attributed back to this
49+
// very alloc site.
50+
AllocTrackerInternalGuard atg;
4351
std::lock_guard<std::mutex> lk(lexer_track_mu());
4452
lexer_track_map()[p] = tokenText ? tokenText : "";
4553
}
4654

4755
void lexer_track_free(std::string *p) noexcept {
4856
if (!p || tl_inside) return;
4957
ReentryGuard g;
58+
// Match the alloc side so the matching internal frees during erase do
59+
// not flag as orphan-frees (alloc was untracked, free must be too).
60+
AllocTrackerInternalGuard atg;
5061
std::lock_guard<std::mutex> lk(lexer_track_mu());
5162
auto & m = lexer_track_map();
5263
auto it = m.find(p);
@@ -55,6 +66,7 @@ namespace das {
5566

5667
int dump_lexer_string_leaks(FILE *out) noexcept {
5768
ReentryGuard g;
69+
AllocTrackerInternalGuard atg;
5870
std::lock_guard<std::mutex> lk(lexer_track_mu());
5971
auto & m = lexer_track_map();
6072
if (m.empty()) return 0;

0 commit comments

Comments
 (0)