Bug 11149 – Runtime.args no longer available in static constructors.

Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P2
Component
druntime
Product
D
Version
D2
Platform
All
OS
Linux
Creation time
2013-09-30T11:30:00Z
Last change time
2013-10-30T00:26:57Z
Assigned to
code
Creator
mike

Comments

Comment #0 by mike — 2013-09-30T11:30:58Z
With git head/2.064 core.runtime.Runtime.args always returns null when called from a static constructor, with 2.063 it used to return the commandline args. Calling it from main works in both versions. ---- import core.runtime; string[] test; shared static this() { test = Runtime.args; } void main() { assert(test !is null); } ---- The assert fails with git head/2.064.
Comment #1 by andrej.mitrovich — 2013-10-01T04:36:46Z
Any platform details? I can't reproduce this on Win7 (using -m32) with these recent commits: dmd: e0a201bbf80fb7bfbc7e5caf2c29921c3bddf5e3 druntime: 12d535030de97835b4c2fb96d079942d93ea708e phobos: d744bec6d4500d6cb6f43011beefc7765dd0e5ce
Comment #2 by mike — 2013-10-01T10:31:00Z
Linux, both 64 and 32 bits.
Comment #3 by bugzilla — 2013-10-08T02:17:05Z
This is working for me with dmd 2.064 head.
Comment #4 by andrej.mitrovich — 2013-10-08T05:36:04Z
(In reply to comment #3) > This is working for me with dmd 2.064 head. On Linux?
Comment #5 by code — 2013-10-08T09:48:20Z
*** Issue 11191 has been marked as a duplicate of this issue. ***
Comment #6 by code — 2013-10-08T10:03:19Z
This is a regression caused by moving the module initialization into C's .ctor/.dtor sections. Not sure how to resolve this right now. BTW, I don't that adding args/cArgs was a good idea in the first place. They provide global access to mutable data but the exact semantics remain unclear, e.g. how is mutating args reflected in main's args and vice versa.
Comment #7 by andrej.mitrovich — 2013-10-08T10:20:03Z
(In reply to comment #6) > BTW, I don't that adding args/cArgs was a good idea in the first place. Some libraries require the C arguments during initialization routines. If you try to initialize such a library in a module constructor then core.runtime is the only way of getting to the main() arguments. (In reply to comment #6) > how is mutating args reflected in main's args and vice versa. It's not reflected since a copy is made in _d_run_main. But I guess this should be documented.
Comment #8 by code — 2013-10-14T03:50:27Z
(In reply to comment #7) > It's not reflected since a copy is made in _d_run_main. But I guess this should > be documented. The arguments are not copied. > This is a regression caused by moving the module initialization into C's .ctor/.dtor sections. Other than poking around in glibc's internals we can only resolve this issue by delaying D's initialization until C's main again. I'll look into this.
Comment #9 by andrej.mitrovich — 2013-10-14T07:26:55Z
(In reply to comment #8) > (In reply to comment #7) > > It's not reflected since a copy is made in _d_run_main. But I guess this should > > be documented. > > The arguments are not copied. I'm not seeing that: ----- import core.runtime; import std.stdio; import std.string; void main(char[][] args) { auto c_args = Runtime.cArgs; printf("%s\n", c_args.argv[0]); c_args.argv[0] = cast(char*)("foobar\0".dup.ptr); printf("%s\n", c_args.argv[0]); writeln(args[0]); } ----- $ rdmd test.d > C:\Users\ADMINI~1\AppData\Local\Temp\.rdmd\rdmd-test.d-E4AFE2A9EC3418A8D53133284F27D58A\test.exe > foobar > C:\Users\ADMINI~1\AppData\Local\Temp\.rdmd\rdmd-test.d-E4AFE2A9EC3418A8D53133284F27D58A\test.exe
Comment #10 by code — 2013-10-17T22:07:20Z
(In reply to comment #9) > > The arguments are not copied. > > I'm not seeing that: > Yes, the C args are copied to the D args. But the C args themselves are not copied. If you run a custom C main this might cause problems but that is a programming error we don't need to fix. Another problem is when you have a C program that links against a D library, we don't have access to main's arguments here. Same issue for shared libraries where providing access to main arguments hardly makes sense. I'm a bit annoyed by this issue because it's so obviously wrong to provide global access to main's arguments before main gets called. If someone wanted global access they could just copy the arguments into a global variable.
Comment #11 by andrej.mitrovich — 2013-10-18T06:58:53Z
(In reply to comment #10) > (In reply to comment #9) > > > The arguments are not copied. > > > > I'm not seeing that: > > > Yes, the C args are copied to the D args. > But the C args themselves are not copied. > If you run a custom C main this might cause problems but > that is a programming error we don't need to fix. But C libraries probably already expect this behavior. That's the only thing cArgs is for really, to interface with those C libs.
Comment #12 by bugzilla — 2013-10-22T14:25:36Z
Martin, what do we do about this one?
Comment #13 by code — 2013-10-23T04:21:48Z
(In reply to comment #12) > Martin, what do we do about this one? I don't know yet but try to find a solution as soon as I have time.
Comment #14 by doob — 2013-10-23T04:56:19Z
(In reply to comment #13) > I don't know yet but try to find a solution as soon as I have time. Could you read /proc/self/cmdline ?
Comment #15 by code — 2013-10-23T08:10:32Z
(In reply to comment #14) > > I don't know yet but try to find a solution as soon as I have time. > > Could you read /proc/self/cmdline ? Thanks for the idea Jacob. It would solve the regression but it's not portable. So once we port the shared library bits to FreeBSD/OSX it will break on those platforms. NB: Shared libraries were the reason to move the init/fini calls.
Comment #16 by doob — 2013-10-23T08:26:27Z
(In reply to comment #15) > Thanks for the idea Jacob. It would solve the regression but it's not portable. > So once we port the shared library bits to FreeBSD/OSX it will break on those > platforms. > > NB: Shared libraries were the reason to move the init/fini calls. None of this low level stuff is portable. FreeBSD: using sysctl with KERN_PROC_ARGS looks like it would to the trick. See: http://www.freebsd.org/cgi/man.cgi?query=sysctl&sektion=3&apropos=0&manpath=FreeBSD+9.2-RELEASE https://github.com/D-Programming-Language/phobos/blob/master/std/file.d#L1650 Mac OS X: _NSGetArgv and _NSGetArgc. See /usr/include/crt_externs.h. Windows (if needed): GetCommandLine. See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683156.aspx
Comment #17 by mailnew4ster — 2013-10-23T08:32:54Z
For Windows there's also CommandLineToArgvW.
Comment #18 by code — 2013-10-25T08:44:13Z
Thanks, that should work indeed. There is at least another regression due to the implicit init/fini of druntime (bug 11309). So I'll fix this and the other bug by make the initialization of shared D libraries explicit. There are a few more reasons for this.
Comment #19 by doob — 2013-10-25T08:59:00Z
BWT, I forgot to mention this. If I recall correctly,_NSGetArgv and _NSGetArgc are private functions. That means, they are not allowed in sandboxed applications, that is, applications in App Store, both on Mac OS X and iOS. I don't know if this is something we would like to care about. On the other hand we already use _NSGetEnviron in std.process. But all of these are mentioned in the documentation of NSApplicationMain, here: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Miscellaneous/AppKit_Functions/Reference/reference.html#//apple_ref/c/func/NSApplicationMain Question, how is the runtime initialized now? I mean, is it initialized in a shared module constructor?
Comment #20 by code — 2013-10-25T09:14:31Z
(In reply to comment #19) > Question, how is the runtime initialized now? I mean, is it initialized in a > shared module constructor? At least on linux it is done from .ctor/.dtor functions that call _d_dso_registry. This is the similar to __attribute__((constructor))/__attribute__((destructor)) functions.
Comment #21 by doob — 2013-10-25T09:18:34Z
(In reply to comment #20) > At least on linux it is done from .ctor/.dtor functions that call > _d_dso_registry. > This is the similar to __attribute__((constructor))/__attribute__((destructor)) > functions. How does the compiler make sure that the .ctor that initializes the runtime is run before any user shared module constructors?
Comment #22 by bugzilla — 2013-10-26T13:41:20Z
I'd like to get 2.064 release finalized. That means this regression needs to be fixed, or deferred. What do you guys think?
Comment #23 by doob — 2013-10-26T15:11:03Z
Another idea that could work is to not use .ctor for the shared module constructors, as before. Then have a single .ctor that initializes the runtime. The shared module constructors would be run from C main/rt_init as before.
Comment #24 by code — 2013-10-29T13:05:16Z
(In reply to comment #22) > I'd like to get 2.064 release finalized. That means this regression needs to be > fixed, or deferred. What do you guys think? We can't defer it, because it has too much impact IMO. For example vibe.d uses Runtime.args to process command line arguments. There are probably more tools taking this approach all of which would break. I filed the underlying issue as bug 11378 and currently work on a fix.
Comment #25 by bugzilla — 2013-10-29T13:19:10Z
(In reply to comment #24) > I filed the underlying issue as bug 11378 and currently work on a fix. Thank you!
Comment #26 by github-bugzilla — 2013-10-30T00:13:25Z
Commit pushed to master at https://github.com/D-Programming-Language/druntime https://github.com/D-Programming-Language/druntime/commit/d3c89cf1894aefa884303344a18436841eae0744 fix Issue 11149 - Runtime.args no longer available in static constructor - This got fixed by reverting the order of initialization. - Add unittest