digitalmars.D.bugs - [Issue 14934] New: GC interface doesn't allow safe extension of a
- via Digitalmars-d-bugs (62/62) Aug 19 2015 https://issues.dlang.org/show_bug.cgi?id=14934
https://issues.dlang.org/show_bug.cgi?id=14934 Issue ID: 14934 Summary: GC interface doesn't allow safe extension of a memory range Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: normal Priority: P1 Component: druntime Assignee: nobody puremagic.com Reporter: code benjamin-thaut.de When extending a existing memory block with realloc which may contain pointers into the D GC heap the first implementation that comes to mind is: void* reallocImpl(void* oldPtr, size_t newSize) { void* newPtr = realloc(oldPtr, newSize); //GC Point 1 GC.addRange(newPtr); //GC Point 2 GC.removeRange(oldPtr); return newPtr; } This implementation has many issues however. 1) If realloc allocated a new block of memory and freed the old one, the following issue arises. If the GC triggres at either GC Point 1 or GC Point 2 (from a different thread), the GC will read the old memory block which is freed. The c-spec states that you should not read this memory after calling realloc. 2) If realloc did not allocate a new block but extended the existing one, the GC.addRange call will not do anything because the underling Treap container ignores duplicates. The remove range call will then remove the old memory block from the list and as a result the GC will loose any knowdelge about this memory block. So a better implementation would look like this. void* reallocImpl(void* oldPtr, size_t newSize) { GC.disable(); GC.removeRange(oldPtr); // GC Point 1 void* newPtr = realloc(oldPtr, newSize); // GC Point 2 GC.addRange(newPtr); GC.enable(); return newPtr; } This would work if GC.disable would actually guarantee that the GC never runs. But as the GC might still run in out of memory situations it can happen that is triggered in either GC Point 1 or GC Point 2. If this happens the GC will not scan either the old or the new memory block. I suggest that we add a function to the GC interface that allows safe updating of a memory range void* updateRange(void* ptr, scope void* delegate() updateFunc); updateFunc would be called within the GC lock, preventing any of the issues described above. void* reallocImpl(void* oldPtr, size_t newSize) { return GC.updateRange(oldPtr, (){ return realloc(oldPtr, newSize); }); } --
Aug 19 2015