Bug 20430 – [Regression 2.089.0] DLL Runtime.terminate() hangs

Status
NEW
Severity
regression
Priority
P1
Component
druntime
Product
D
Version
D2
Platform
x86_64
OS
Windows
Creation time
2019-12-04T23:06:30Z
Last change time
2024-12-07T13:39:51Z
Keywords
dll
Assigned to
No Owner
Creator
Radu Racariu
Moved to GitHub: dmd#17184 →

Comments

Comment #0 by radu.racariu — 2019-12-04T23:06:30Z
The following program and dll will hang when build with 2.089.0 and will work on older versions: dll.d ` module dll; import core.sys.windows.windows; import core.stdc.stdio : printf; extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { import core.runtime : Runtime; switch (ulReason) { case DLL_PROCESS_ATTACH: printf("DLL_PROCESS_ATTACH\n"); Runtime.initialize(); break; case DLL_PROCESS_DETACH: printf("DLL_PROCESS_DETACH\n"); Runtime.terminate(); printf("Terminated!\n"); break; case DLL_THREAD_ATTACH: printf("DLL_THREAD_ATTACH\n"); return false; case DLL_THREAD_DETACH: printf("DLL_THREAD_DETACH\n"); return false; default: } return true; } /// DLL entry point export extern (C) void extInit() { printf("Called `extInit` from the DLL\n"); } ` program.d ` module program import core.runtime; import core.stdc.stdio; import core.sys.windows.windows; void load() { string dll = "bug.dll"; HMODULE handle; FARPROC fp; printf("Start Dynamic Link...\n"); handle = cast(HMODULE) Runtime.loadLibrary(dll); if (handle is null) { printf("error loading %.*s\n", dll.length, dll.ptr); return; } // bind the extInit function fp = GetProcAddress(handle, "extInit"); if (fp is null) { printf("error loading symbol extInit()\n"); return; } extInit = cast(ExtInitFunc) fp; } /// Ext register entry point alias ExtInitFunc = void function(); ExtInitFunc extInit; int main() { printf("Start loading.\n"); load(); printf("End...\n"); return 0; } ` Working output (2.088.1) ` Start loading. Start Dynamic Link... DLL_PROCESS_ATTACH End... DLL_PROCESS_DETACH Terminated! ` Bad output (2.089.0) ` End... DLL_THREAD_ATTACH DLL_THREAD_DETACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_ATTACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_PROCESS_DETACH `
Comment #1 by radu.racariu — 2019-12-04T23:09:11Z
The bad output got truncated, looks like: ` Start loading. Start Dynamic Link... DLL_PROCESS_ATTACH End... DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_PROCESS_DETACH `
Comment #2 by kinke — 2019-12-06T17:10:23Z
Can reproduce; there's one less thread_detach than _attach. Output with my quad-core: > program.exe DLL_PROCESS_ATTACH End... DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_PROCESS_DETACH > program.exe --DRT-gcopt=parallel:0 Start loading. Start Dynamic Link... DLL_PROCESS_ATTACH End... DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_PROCESS_DETACH > program.exe --DRT-gcopt=disable:1 Start loading. Start Dynamic Link... DLL_PROCESS_ATTACH End... DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_ATTACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_THREAD_DETACH DLL_PROCESS_DETACH The output is the same but the program doesn't hang anymore when using a more complete DllMain (extended core.sys.windows.dll.SimpleDllMain mixin): extern (Windows) BOOL DllMain(HINSTANCE hInstance, uint ulReason, void* reserved) { import core.sys.windows.winnt; import core.sys.windows.dll : dll_process_attach, dll_process_detach, dll_thread_attach, dll_thread_detach; switch (ulReason) { default: assert(0); case DLL_PROCESS_ATTACH: printf("DLL_PROCESS_ATTACH\n"); return dll_process_attach( hInstance, true ); case DLL_PROCESS_DETACH: printf("DLL_PROCESS_DETACH\n"); dll_process_detach( hInstance, true ); return true; case DLL_THREAD_ATTACH: printf("DLL_THREAD_ATTACH\n"); return dll_thread_attach( true, true ); case DLL_THREAD_DETACH: printf("DLL_THREAD_DETACH\n"); return dll_thread_detach( true, true ); } }
Comment #3 by r.sagitario — 2019-12-07T19:17:24Z
Indeed, calling Runtime.initialize(); and Runtime.terminate(); in DllMain is not good enough (and never really has been). Is this still proposed somewhere? Is this a documentation issue?
Comment #4 by radu.racariu — 2019-12-12T20:22:59Z
That was using a sample form https://wiki.dlang.org/Win32_DLLs_in_D#D_code_calling_D_code_in_DLLs Maybe that needs fixing.
Comment #5 by r.sagitario — 2019-12-14T09:01:39Z
> https://wiki.dlang.org/Win32_DLLs_in_D#D_code_calling_D_code_in_DLLs IMO the gcProxy approach is so limited (no multi-threading, no sharing of other resources) that we should rather remove that section or add a large flashing warning at the top. We need something like https://dconf.org/2016/talks/thaut.html to support sharing the runtime across DLLs. If someone actually uses the gcProxy, a simple fix should be to disable parallel marking by adding this line extern (C) __gshared string[] rt_options = ["gcopt=parallel:0"];
Comment #6 by robert.schadek — 2024-12-07T13:39:51Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/17184 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB