Bug 11378 – implicit runtime initialization/finalization is broken

Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P2
Component
druntime
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-10-29T07:04:00Z
Last change time
2013-10-31T07:50:45Z
Keywords
dll, pull
Assigned to
code
Creator
code

Comments

Comment #0 by code — 2013-10-29T07:04:31Z
This change was introduced with https://github.com/D-Programming-Language/druntime/pull/590 (commit https://github.com/dawgfoto/druntime/commit/68eee299e28ee51421aac8fd5920edeb814c5b54). It was added to perform automatic initialization/finalization when loading shared libraries. The change of the initialization order introduced some regressions (Bug 11149, Bug 10976 and Bug 11309). Furthermore the runtime initialization takes ownership of the main thread (calls thread_attachThis) which may be unintended in a C executable that uses a D library. There are basically two ways to fix this. A. Remove all implicit initialization/finalization. All linked D libraries (including druntime) are initialized/finalized by _d_run_main or by calling rt_init/rt_term for C executable. Dynamically loaded shared libraries would need to be initialized after loading and finalized before unloading. This required a ctor/dtor API in druntime that can be called from within a shared library (might use the return address to determine the calling DSO) to support D libraries in C plugin frameworks that only allow predefined init/fini hooks. We should also add an API that takes a library handle and runs ctors/dtors. When moving the ctor/dtor calls out of libc's _d_dso_registry the calls need to be synchronized. B. Remove only implicit initialization/finalization of linked libraries. All linked D libraries (including druntime) are initialized/finalized by _d_run_main or by calling rt_init/rt_term for C executable. Dynamically loaded shared libraries would still be initialized implicitly (this includes calling rt_init/rt_term if it hasn't been called before and implicitly attaching threads that load a D library). The main difficulty here is to detect in _d_dso_registry whether the calling DSO was linked or dynamically loaded. I'm currently working on approach B because it avoids complicating the usage of shared libraries.
Comment #1 by code — 2013-10-29T12:54:51Z
C. Perform implicit init/fini only after rt_init was called. All linked D libraries (including druntime) are initialized/finalized by _d_run_main or by calling rt_init/rt_term for C executable. All dynamic libraries loaded before calling rt_init are only initialized when calling rt_init. Likewise calling rt_term will terminate all currently loaded libraries. This provides init control for C executables with a simple/existing API while solving the init order issues.
Comment #2 by code — 2013-10-29T16:47:12Z
Comment #3 by github-bugzilla — 2013-10-30T00:13:11Z
Commits pushed to master at https://github.com/D-Programming-Language/druntime https://github.com/D-Programming-Language/druntime/commit/dc559c3ef2916102c6f295d70c3941644e545bf2 make runtime initialization/finalization explicit - fix Issue 11378 - implicit runtime initialization/finalization is broken - C programs need to call rt_init in order to initialize the runtime and all shared libraries. - After rt_init was called shared libraries are initialized on loading and finalized on unloading. - C programs need to call rt_term in order to finalize the runtime and all shared libraries. https://github.com/D-Programming-Language/druntime/commit/9ab0b70dc957f6f40cf9683888fe1e779b110e49 Merge pull request #649 from dawgfoto/fix11378 fix Issue 11378 - implicit runtime initialization/finalization is broken
Comment #4 by github-bugzilla — 2013-10-30T00:21:40Z
Commit pushed to 2.064 at https://github.com/D-Programming-Language/druntime https://github.com/D-Programming-Language/druntime/commit/7c396ef4080737928e68bdb2550e403b87fe379f Merge pull request #649 from dawgfoto/fix11378 fix Issue 11378 - implicit runtime initialization/finalization is broken
Comment #5 by mk — 2013-10-30T10:34:26Z
I've noticed the following program now segfaults on exit. In case calling exit() is now not possible, please document the correct way how to do it (I haven't found any). --------------------- import std.concurrency, std.c.stdlib; int main(string[] args) { spawn(&thread); return 0; } void thread() { while(1) { receive( (OwnerTerminated o) { exit(EXIT_SUCCESS); } /* segfault on exit */ ); } } ---------------------
Comment #6 by kai — 2013-10-30T13:52:11Z
After merge of pull request #649 I can't compile druntime. Error message is: src\rt\dmain2.d(442): Error: function object.Throwable.toString () is not callab le using argument types (void delegate(const(char)[] buf) nothrow) src\rt\dmain2.d(450): Error: function object.Throwable.toString () is not callab le using argument types (void delegate(const(char)[] buf) nothrow) The new overloaded method toString() is missing ib object.di / object_.d
Comment #7 by code — 2013-10-30T13:54:00Z
(In reply to comment #5) > I've noticed the following program now segfaults on exit. In case calling > exit() is now not possible, please document the correct way how to do it (I > haven't found any). > You have a race condition because both the main thread and the spawned thread run the process destruction. You shouldn't call exit in your thread but simply break the infinite loop.
Comment #8 by code — 2013-10-30T13:59:57Z
(In reply to comment #6) > After merge of pull request #649 I can't compile druntime. > I see, that overload is only available on master but is missing on 2.064. So cherry-picking didn't work for this pull.
Comment #9 by mk — 2013-10-30T14:23:11Z
(In reply to comment #7) > You shouldn't call exit in your thread but simply break the infinite loop. OK, that's probably workable, would be nice if there was some function to correctly exit the thread at any moment, though. Case closed for me.
Comment #10 by bugzilla — 2013-10-30T20:19:42Z
Not sure - is this fixed or not for 2.064?
Comment #11 by code — 2013-10-30T23:10:27Z
(In reply to comment #9) > OK, that's probably workable, would be nice if there was some function to > correctly exit the thread at any moment, though. Case closed for me. Exiting a thread is different from exiting the process and even that would require more for a correct shutdown than C's exit function. The only mechanism that we have which could correctly unwind a stack and free all resources is throwing an Exception. What's your use-case for this?
Comment #12 by doob — 2013-10-31T00:29:11Z
(In reply to comment #11) > Exiting a thread is different from exiting the process and even that would > require more for a correct shutdown than C's exit function. > > The only mechanism that we have which could correctly unwind a stack and free > all resources is throwing an Exception. What's your use-case for this? Can't we setup a callback using "atexit" which correctly terminates the runtime?
Comment #13 by code — 2013-10-31T07:50:45Z
(In reply to comment #12) > Can't we setup a callback using "atexit" which correctly terminates the > runtime? No, because then we couldn't clean up the stack. I still don't understand the need for this. I don't even know if a C program can be terminated by a call to exit from another thread.