From 99570bc897eea692974491c5d6339eabfd1f412a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Sat, 23 Nov 2024 08:17:34 +0100 Subject: [PATCH] Fix InvalidMemoryOperationError caused by leaking an open FileStream to the GC. --- source/vibe/core/file.d | 12 +++++++++++- tests/vibe.core.file.gcleak.d | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/vibe.core.file.gcleak.d diff --git a/source/vibe/core/file.d b/source/vibe/core/file.d index 8be5b15..9a76f60 100644 --- a/source/vibe/core/file.d +++ b/source/vibe/core/file.d @@ -699,9 +699,19 @@ scope: ~this() nothrow { + import core.memory : GC; + import core.stdc.stdio : fprintf, stderr; + static if (is(typeof(&eventDriver.files.isUnique))) { if (this.isOpen) { - if (m_ctx.driver is (() @trusted => cast(shared)eventDriver)()) { + if (GC.inFinalizer) { + () @trusted { + auto path = m_ctx.path.toString(); + fprintf(stderr, "Warning: Leaking open FileStream handle because the instance was leaked to the GC (%.*s)\n", + cast(int)path.length, path.ptr); + } (); + m_fd = FileFD.invalid; + } else if (m_ctx.driver is (() @trusted => cast(shared)eventDriver)()) { if (eventDriver.files.isUnique(m_fd)) { try close(); catch (Exception e) logException(e, "Closing unclosed FileStream during destruction failed"); diff --git a/tests/vibe.core.file.gcleak.d b/tests/vibe.core.file.gcleak.d new file mode 100644 index 0000000..1807802 --- /dev/null +++ b/tests/vibe.core.file.gcleak.d @@ -0,0 +1,20 @@ +/+ dub.sdl: + dependency "vibe-core" path=".." ++/ +module test; + +import vibe.core.file; + + +// this test ensures that leaking an open FileStream will not crash the +// application +void main() +{ + auto fil = new FileStream; + *fil = openFile("test.tmp", FileMode.createTrunc); + fil = null; + + ubyte[] arr; + foreach (i; 0 .. 1000) + arr ~= "1234567890"; +}