Bug 23611 – Zombie heap leak proof of concept: linked list in dead resized array

Status
NEW
Severity
minor
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2023-01-09T13:11:13Z
Last change time
2024-12-13T19:26:37Z
Assigned to
No Owner
Creator
FeepingCreature
Moved to GitHub: dmd#20211 →

Comments

Comment #0 by default_357-line — 2023-01-09T13:11:13Z
In my post A GC Memory Usage Experiment https://forum.dlang.org/post/[email protected] , I suggested the existence of a GC leak caused by downsizing data structures. This bug report poses a proof-of-concept for such a leak: struct S { S[] parent; } void main() { S parent; while (true) { S[] link = [S(null), parent]; link.length = 1; parent = S(link); } } As can be seen, at any given point almost no memory in this program is actually live: `parent` can only point at an array of the value `[S(null)]`, and all other variables get overwritten on every loop pass. And yet, this program leaks an unbounded amount of memory. (I recommend running with -m32 to test.) What's happening is that the program forms a linked list in memory that is dead, but that the GC cannot determine is dead. Because the GC has no type-level understanding of allocated memory, it sees `parent` as a pointer to a linked list of allocations; that the linking element lives in an unreferenced part of the array is outside of its purview. In theory this could be fixed by being smarter about arrays marking memory regions as alive: a slice need only mark as alive the part of the array it actually points at, which would allow the recursive mark to skip the dead parent reference.
Comment #1 by default_357-line — 2023-01-09T13:20:45Z
Interestingly, this issue cannot be provoked with associative arrays - probably deleting a key zeroes out the associated value.
Comment #2 by ibuclaw — 2023-01-09T19:18:20Z
(In reply to FeepingCreature from comment #0) > In my post A GC Memory Usage Experiment > https://forum.dlang.org/post/[email protected] , I > suggested the existence of a GC leak caused by downsizing data structures. > This bug report poses a proof-of-concept for such a leak: > > struct S { > S[] parent; > } > > void main() { > S parent; > while (true) { > S[] link = [S(null), parent]; > link.length = 1; I assume no zeroing is done here because you might have other slices to the data. auto slice = link[0 .. $]; link.length = 1; assert(slice[1] == parent);
Comment #3 by default_357-line — 2023-01-10T02:57:13Z
Well, there's lots of ways to avoid this issue. Zeroing, as you say. I'm just putting up this bug to note it's a straightforward issue as it stands. We're used to treating the GC the way we know it works rather than the way it theoretically could work, doing array.dup to cut off dead elements, etc., and at any rate the GC isn't *obligated* to collect anything ever, etc etc. But naively, this is still surprising behavior.
Comment #4 by robert.schadek — 2024-12-13T19:26:37Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/20211 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB